<?xml version="1.0" encoding="UTF-8" standalone="no"?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:gd="http://schemas.google.com/g/2005" xmlns:georss="http://www.georss.org/georss" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:thr="http://purl.org/syndication/thread/1.0"><id>tag:blogger.com,1999:blog-6877522804921028548</id><updated>2025-11-09T10:15:25.343+05:30</updated><category term="AWS"/><category term="Spring Cloud"/><category term="Java"/><category term="Spring Data JPA"/><category term="Unit Testing"/><category term="Mockito"/><category term="Spring Boot"/><category term="JDK"/><category term="JUnit 5"/><category term="Maven"/><category term="coding problem"/><title type="text">Learn Java Skills</title><subtitle type="html"> </subtitle><link href="https://www.learnjavaskills.in/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default?redirect=false" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/" rel="alternate" type="text/html"/><link href="http://pubsubhubbub.appspot.com/" rel="hub"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default?start-index=26&amp;max-results=25&amp;redirect=false" rel="next" type="application/atom+xml"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><generator uri="http://www.blogger.com" version="7.00">Blogger</generator><openSearch:totalResults>45</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><xhtml:meta content="noindex" name="robots" xmlns:xhtml="http://www.w3.org/1999/xhtml"/><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-3431629358293153845</id><published>2025-02-02T19:42:00.000+05:30</published><updated>2025-02-02T19:42:21.671+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="Mockito"/><category scheme="http://www.blogger.com/atom/ns#" term="Unit Testing"/><title type="text">Mockito Exception Throwing for Unit Testing | Learn Java Skills</title><content type="html">&lt;p&gt;There is a standard coding practice in Java application development to capture the exception using the try-catch block, and there may be some business logic in the catch block that you wish to unit test.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;If you are wondering, is there a possibility of using the mockito framework to test the catch block?&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&lt;a href="https://www.learnjavaskills.in/search/label/Mockito"&gt;Mockito&lt;/a&gt; makes it simple to throw an exception when invoking the method.&lt;/p&gt; &lt;br/&gt; 

&lt;p&gt;In this quick lesson, we'll look at how to throw an exception and &lt;a href="https://www.learnjavaskills.in/search/label/Unit%20Testing"&gt;unit test&lt;/a&gt; the catch block. Alternatively, you may test your business logic to examine how exceptions are handled in your application.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/mockito-tutorial/tree/main" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;strike&gt;toc&lt;/strike&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwiKzbIfbPKSLncL3y8Q9kqMdcncl3Am9VDXj6b2vsDTIbd0pA4lAx2bt37theyBP3KHelssWMgKq8qoqoSaKxZvZ6G5z3iiGh1z844Hh1q9X-vNoIswe8nU6uSfeTv5EOlGkTUR8TNKf4dsAfQbxgtrzwKmuUR4jDTymS6gn9jerBcsEqsabaOw1Nq-_8/s1600/Mockito%20Exception%20Throwing%20Thumbnail.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Mockito Exception Throwing for Unit Testing thumbnail image" border="0" data-original-height="720" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwiKzbIfbPKSLncL3y8Q9kqMdcncl3Am9VDXj6b2vsDTIbd0pA4lAx2bt37theyBP3KHelssWMgKq8qoqoSaKxZvZ6G5z3iiGh1z844Hh1q9X-vNoIswe8nU6uSfeTv5EOlGkTUR8TNKf4dsAfQbxgtrzwKmuUR4jDTymS6gn9jerBcsEqsabaOw1Nq-_8/s1600/Mockito%20Exception%20Throwing%20Thumbnail.png"/&gt;&lt;/a&gt;&lt;/div&gt;



&lt;h2&gt;Code Overview&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;In this lesson, &lt;b&gt;we'll look at how we may throw exceptions on both the void and non-void methods.&lt;/b&gt;&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;As a result, I created the following code to cover both functions: I'll teach you how to throw an exception on the non-void &lt;code&gt;notificationService.sendNotification()&lt;/code&gt; method and the void &lt;code&gt;transactionRepository.saveNetBankingTransaction()&lt;/code&gt; method.
&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in .learnjavaskills.mockitotutorial.service;

 import in .learnjavaskills.mockitotutorial.repository.TransactionRepository;

 import java.math.BigDecimal;
 import java.util.Objects;
 import java.util.concurrent.TimeUnit;

 public class TransactionService {
    private TransactionRepository transactionRepository;

    private NotificationService notificationService;
    public TransactionService(TransactionRepository transactionRepository, NotificationService notificationService) {
        this.transactionRepository = transactionRepository;
        this.notificationService = notificationService;
    }

    public void netBankingTransaction(String username, String password,
        BigDecimal amount, Long transferAccountNumber) throws InterruptedException {
        boolean isValidUser = authenticateUser(username, password);
        if (isValidUser) {
            boolean isTransferSuccess = transferAmount(transferAccountNumber, username, amount);
            if (isTransferSuccess) {
                // Send notification to user
                try {
                    boolean isNotificationSend = notificationService.sendNotification("toEmail@address.com", "Transaction success for " + amount, "Hi " + username + " \n Successfully transfer amount " + amount);
                } catch (Exception exception) {
                    TimeUnit.SECONDS.sleep(10L);
                    // Re-Trying sending notification
                    boolean isNotificationSend = notificationService.sendNotification("toEmail@address.com", "Transaction success for " + amount, "Hi " + username + " \n Successfully transfer amount " + amount);
                }

                // save net banking transaction
                try {
                    transactionRepository.saveNetBankingTransaction(username, amount);
                } catch (Exception exception) {
                    TimeUnit.SECONDS.sleep(10L);
                    // Re-Trying to save net banking transaction
                    transactionRepository.saveNetBankingTransaction(username, amount);
                }
            }
        }
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Non-Void Return Type Method&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Let's start by learning &lt;b&gt;how to throw an exception on the non-void return type method&lt;/b&gt;. This is as simple as mocking the object and returning some dummy value.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;In the following example, I've mock the &lt;code&gt;NotificationService&lt;/code&gt; class's &lt;code&gt;sendNotification()&lt;/code&gt; method, which is in charge of notifying the user. According to the business logic in the above code, &lt;b&gt;if we find an error while notifying the end user, it will retry notifying them after 10 seconds&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Let's see how we can mock the &lt;b&gt;sendNotification()&lt;/b&gt; function to throw an exception and check that the &lt;b&gt;sendNotification()&lt;/b&gt; method should be executed twice according to our business logic.&lt;/p&gt; &lt;br/&gt;



&lt;pre&gt;&lt;code class = "java"&gt; package in .learnjavaskills.mockitotutorial.service;

 import in .learnjavaskills.mockitotutorial.exception.TransactionException;
 import in .learnjavaskills.mockitotutorial.repository.TransactionRepository;
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.*;
 import org.mockito.junit.jupiter.MockitoExtension;

 import java.math.BigDecimal;

 @ExtendWith(MockitoExtension.class)
 class TransactionServiceTest {
    @Mock
    private TransactionRepository transactionRepository;

    @Mock private NotificationService notificationService;

    @InjectMocks
    private TransactionService transactionService;

    @Test
    void testWhenExceptionThrownWileSendingNotification() throws InterruptedException {
        BDDMockito.given(notificationService.sendNotification(ArgumentMatchers.any(), ArgumentMatchers.any(),
                ArgumentMatchers.any()))
            .willThrow(TransactionException.class);

        // verifying excetion is thrown with TransactionException
        Assertions.assertThatThrownBy(() - &gt; transactionService.netBankingTransaction("LearnJavaSkills.in",
                "password", BigDecimal.TEN, 1234567890L))
            .isExactlyInstanceOf(TransactionException.class);

        //  verifying 2 times sendNotification() method should invoke because in catch block also we are re-trying to send notification
        BDDMockito.verify(notificationService, Mockito.times(2))
            .sendNotification(ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any());
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Void Return Type Method&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Let's look at &lt;b&gt;how we may throw an exception on the void method now&lt;/b&gt;. Throwing an exception on the void return type method differs somewhat from the non-void return type method shown in the previous example.&lt;/p&gt; &lt;br/&gt; 

&lt;p&gt;To test the catch block code, we mock &lt;code&gt;transactionRepository&lt;/code&gt; to raise a &lt;code&gt;TransactionException&lt;/code&gt; when the &lt;code&gt;saveNetBankingTransaction()&lt;/code&gt; method is executed.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;If you thoroughly examined the code overview, you could have seen that if any errors are encountered during saving the net banking transaction, &lt;b&gt;it must re-try after 10 seconds to save the same transaction&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;I also used the &lt;code&gt;BDDMockito.verify()&lt;/code&gt; method to validate this situation.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 void testWhenExceptionThrownWhileSavingNetBankingTransaction() {
    // mocking transactionRepository to throw TransactionException when saveNetBankingTransaction() invoke
    BDDMockito.doThrow(TransactionException.class)
        .when(transactionRepository)
        .saveNetBankingTransaction(ArgumentMatchers.any(), ArgumentMatchers.any());

    // verifying exception are thrown which mock in the above
    Assertions.assertThatThrownBy(() - &amp;gt; transactionService.netBankingTransaction(&amp;quot;LearnJavaSkills.in&amp;quot;,
            &amp;quot;password&amp;quot;,
            BigDecimal.TEN,
            1234567890L))
        .isExactlyInstanceOf(TransactionException.class);

    // verifying saveNetBankingTransaction method invoke two times as per the business logic
    BDDMockito.verify(transactionRepository, Mockito.times(2))
        .saveNetBankingTransaction(ArgumentMatchers.any(), ArgumentMatchers.any());
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;How to Throw an Exception with a Message&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;&lt;a href="https://www.learnjavaskills.in/search/label/Mockito"&gt;Mockito&lt;/a&gt; allows us to throw exceptions as objects, therefore we can also throw exceptions with messages.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;In our earlier example, we may substitute the Exception object for the Exception class.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;Non-Void Return Type Method - Throw an Exception with a Message&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 void testWhenExceptionThrownWileSendingNotification() throws InterruptedException {
    String message = &amp;quot;Unable to send notification to user&amp;quot;;
    BDDMockito.given(notificationService.sendNotification(ArgumentMatchers.any(), ArgumentMatchers.any(),
            ArgumentMatchers.any()))
        .willThrow(new TransactionException(message));

    Assertions.assertThatThrownBy(() - &amp;gt; transactionService.netBankingTransaction(&amp;quot;LearnJavaSkills.in&amp;quot;,
            &amp;quot;password&amp;quot;,
            BigDecimal.TEN,
            1234567890L))
        .isExactlyInstanceOf(TransactionException.class)
        .hasMessageContaining(message);

    BDDMockito.verify(notificationService, Mockito.times(2))
        .sendNotification(ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any());
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;Void Return Type Method - Throw an Exception with a Message&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java"&gt;  @Test
 void testWhenExceptionThrownWhileSavingNetBankingTransaction() {
     // mocking transactionRepository to throw TransactionException when saveNetBankingTransaction() invoke
     String message = &amp;quot;unable to save net banking transaction&amp;quot;;
     BDDMockito.doThrow(new TransactionException(message))
         .when(transactionRepository)
         .saveNetBankingTransaction(ArgumentMatchers.any(), ArgumentMatchers.any());

     // verifying exception are thrown which mock in the above
     Assertions.assertThatThrownBy(() - &amp;gt; transactionService.netBankingTransaction(&amp;quot;LearnJavaSkills.in&amp;quot;,
             &amp;quot;password&amp;quot;,
             BigDecimal.TEN,
             1234567890L))
         .isExactlyInstanceOf(TransactionException.class)
         .hasMessageContaining(message);

     // verifying saveNetBankingTransaction method invoke two times as per the business logic
     BDDMockito.verify(transactionRepository, Mockito.times(2))
         .saveNetBankingTransaction(ArgumentMatchers.any(), ArgumentMatchers.any());
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Stubbing Multiple Calls&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;&lt;a href="https://www.learnjavaskills.in/search/label/Mockito"&gt;Mockito&lt;/a&gt; is one of the most powerful Java mocking frameworks. Mockito allows us to &lt;b&gt;stub numerous times with various behaviors&lt;/b&gt;, which is highly useful for testing sequential exception handling or forward-thinking behavior.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;If you've been paying attention to our code overview, you'll see that we're retrying to send the notification to the enduser if any errors occur at notifying.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;With mockito, you may stub this &lt;code&gt;sendNotification()&lt;/code&gt; method to throw an exception, and then stub this &lt;code&gt;sendNotification()&lt;/code&gt; method &lt;b&gt;again to return values when sendNotification() is executed the second time&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Let's look at how we'll unit test if we're willing to throw an exception on the initial method called and return values on the re-try attempt.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 void testWhenExceptionThrownWileSendingNotificationStubMultiCall() throws InterruptedException {
    String message = &amp;quot;Unable to send notification to user&amp;quot;;
    BDDMockito.given(notificationService.sendNotification(ArgumentMatchers.any(), ArgumentMatchers.any(),
            ArgumentMatchers.any()))
        .willThrow(new TransactionException(message))
        .willReturn(true);

    transactionService.netBankingTransaction(&amp;quot;LearnJavaSkills.in&amp;quot;,
        &amp;quot;password&amp;quot;,
        BigDecimal.TEN,
        1234567890L);

    BDDMockito.verify(notificationService, Mockito.times(2))
        .sendNotification(ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any());
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/ae6pKiaTO7c?si=tzIqlnO8-dbwIses" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen&gt;&lt;/iframe&gt;
&lt;br/&gt;
&lt;br/&gt;

&lt;h2&gt;Conclussion&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;&lt;a href="https://www.learnjavaskills.in/search/label/Mockito"&gt;Mockito&lt;/a&gt; is a powerful mocking framework for Java applications. We can use the mockito framework to not only mock objects such that they return the values we want, but we can also throw an exception on method call by mocking an object.&lt;/p&gt;

&lt;blockquote&gt;Mockito allows multiple stubbing calls, which implies that if you have numerous calls to that method, you may control the behavior by stubbing all of them at once.(alert-success)&lt;/blockquote&gt;

&lt;p&gt;Multiple stubbing works in combination with the sequential method invocation in your business logic. Assume you've called a method three times, the first two times throwing an exception and the third time being requested to return values.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The method will then throw an exception the first two times it is executed in your business logic, and it will return values the third time.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/mockito-tutorial/tree/main" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;

&lt;p align="right"&gt;&lt;a href="https://www.learnjavaskills.in/2025/02/mock-constructor-in-mockito.html"&gt;(getButton) #text=(Next: Mock constructor in Mockito) #icon=(link) #color=(#2339bd)&lt;/a&gt;&lt;/p&gt;

</content><link href="https://www.learnjavaskills.in/feeds/3431629358293153845/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/11/mockito-exception-throwing.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/3431629358293153845" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/3431629358293153845" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/11/mockito-exception-throwing.html" rel="alternate" title="Mockito Exception Throwing for Unit Testing | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwiKzbIfbPKSLncL3y8Q9kqMdcncl3Am9VDXj6b2vsDTIbd0pA4lAx2bt37theyBP3KHelssWMgKq8qoqoSaKxZvZ6G5z3iiGh1z844Hh1q9X-vNoIswe8nU6uSfeTv5EOlGkTUR8TNKf4dsAfQbxgtrzwKmuUR4jDTymS6gn9jerBcsEqsabaOw1Nq-_8/s72-c/Mockito%20Exception%20Throwing%20Thumbnail.png" width="72"/><thr:total>0</thr:total><georss:featurename>India</georss:featurename><georss:point>20.593684 78.96288</georss:point><georss:box>-7.7165498361788458 43.80663 48.903917836178849 114.11913</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-198026688223879006</id><published>2025-02-02T19:38:00.001+05:30</published><updated>2025-02-02T19:39:04.992+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="Mockito"/><category scheme="http://www.blogger.com/atom/ns#" term="Unit Testing"/><title type="text">How to mock constructor in Mockito</title><content type="html">&lt;p&gt;Creating new objects directly within a method often violates dependency injection principles. Ideally, refactoring to adhere to clean code architecture is the preferred solution.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;However, if refactoring isn't immediately feasible, the following example demonstrates how to mock object creation (constructors) in Java using Mockito.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/mockito-tutorial/tree/main" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx53BXoQw73FwWcjVsJc40qBsW8Uj1Iw-cnk2NsXvk7TR8yPZ-mX2vWlZf6sfNwQIAk2zttCt6XW4txXn6kPgFC4ogOfvvdyRD0AY2JVpl_lSbyC3pS_VemGE4Fvr5lX2CNTzsoR6mXIWlRvhf0PIK4wV6nMtPGH2lkgIMhifEsAfRdFVtTvPYYABkxxvJ/s1600/Constructor-Mocking.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Thumbnail image" border="0" data-original-height="720" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx53BXoQw73FwWcjVsJc40qBsW8Uj1Iw-cnk2NsXvk7TR8yPZ-mX2vWlZf6sfNwQIAk2zttCt6XW4txXn6kPgFC4ogOfvvdyRD0AY2JVpl_lSbyC3pS_VemGE4Fvr5lX2CNTzsoR6mXIWlRvhf0PIK4wV6nMtPGH2lkgIMhifEsAfRdFVtTvPYYABkxxvJ/s1600/Constructor-Mocking.png"/&gt;&lt;/a&gt;&lt;/div&gt;


&lt;strike&gt;toc&lt;/strike&gt;&lt;br/&gt;

&lt;h2&gt;TransactionService class&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;The &lt;code&gt;upiPayment()&lt;/code&gt; method within my &lt;code&gt;TransactionService&lt;/code&gt; class relies on the &lt;code&gt;Account&lt;/code&gt; class to check if UPI payments are enabled for a given account number.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;To avoid invoking the real &lt;code&gt;isUpiAllowed()&lt;/code&gt; method during testing, I intend to mock the Account constructor.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This will allow me to inject a mock Account object that provides a controlled response when its &lt;code&gt;isUpiAllowed()&lt;/code&gt; method is called.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This mocking strategy is generally applicable and can be used with other dependencies, such as &lt;code&gt;RestTemplate&lt;/code&gt; for mocking API responses.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public class TransactionService
 {
   public boolean upiPayment(Long accountNumber, BigDecimal amount) {
     Account account = new Account(); // we'll mock this constructor
     boolean upiAllowed = account.isUpiAllowed(accountNumber, amount);
     if (upiAllowed) {
       System.out.println(&amp;#x22;transaction completed&amp;#x22;);
       return true;
     }
     return false;
   }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;


&lt;pre&gt;&lt;code class = "java"&gt; public class Account {
    public boolean isUpiAllowed(Long accountNumber, BigDecimal amount) {
      System.out.println(&amp;#x22;Checking is UPI transaction active for account &amp;#x22; + accountNumber + &amp;#x22; for amount &amp;#x22; + amount);
      return Objects.nonNull(accountNumber) &amp;#x26;&amp;#x26; accountNumber &amp;#x3E; 1
              Objects.nonNull(amount) &amp;#x26;&amp;#x26; amount.compareTo(BigDecimal.valueOf(5000d)) &amp;#x3C; 0;
   }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Mocking the Account Constructor for JUnit Tests&lt;/h2&gt;
&lt;hr&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 void upiTransaction() {
   try (MockedConstruction&amp;#x3C;Account&amp;#x3E; accountMockedConstruction = Mockito.mockConstruction(Account.class, (mock, context) -&amp;#x3E;
          Mockito.when(mock.isUpiAllowed(ArgumentMatchers.anyLong(), ArgumentMatchers.any()))
                      .thenReturn(true))) {
     boolean transactionStatus = transactionService.upiPayment(1234567890L, BigDecimal.TEN);
     assertTrue(transactionStatus);
   }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;Mockito.mockConstruction() method: Explanation&lt;/h3&gt;
&lt;hr&gt;
&lt;p&gt;Mockito's &lt;code&gt;mockConstruction()&lt;/code&gt; method provides a powerful way to mock the instantiation of new objects, offering greater flexibility than older approaches like &lt;code&gt;whenNew()&lt;/code&gt;.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;It's particularly useful when dealing with classes you don't directly control, or when you need to mock the creation of objects within the system under test.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This approach allows you to intercept and control the behavior of newly created instances, enabling you to isolate dependencies, simulate specific scenarios, and thoroughly test your code&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The following overloaded version of the &lt;code&gt;mockConstructor&lt;/code&gt; method is used in this example.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public static &amp;#x3C;T&amp;#x3E; org.mockito.MockedConstruction&amp;#x3C;T&amp;#x3E; mockConstruction(java.lang.Class&amp;#x3C;T&amp;#x3E; classToMock, org.mockito.MockedConstruction.MockInitializer&amp;#x3C;T&amp;#x3E; mockInitializer) { /* compiled code */ }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;MockInitializer interface: Explanation&lt;/h3&gt;
&lt;hr&gt;

&lt;p&gt;&lt;code&gt;MockInitializer&lt;/code&gt; in Mockito is a powerful mechanism that allows you to customize and extend the initialization process of your mocks.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;It provides a way to execute specific setup logic before mocks are fully initialized, giving you fine-grained control over their behavior and state.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This is particularly useful for handling complex initialization scenarios, setting up default values, or integrating with other testing frameworks.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;To customize our mock, we simply implement the following &lt;code&gt;prepare()&lt;/code&gt; method.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @java.lang.FunctionalInterface
 static interface MockInitializer &amp;#x3C;T&amp;#x3E; {
   void prepare(T t, org.mockito.MockedConstruction.Context context) throws java.lang.Throwable;
 }

 static interface Context {
   int getCount();

   java.lang.reflect.Constructor&amp;#x3C;?&amp;#x3E; constructor();

   java.util.List&amp;#x3C;?&amp;#x3E; arguments();
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Conclussion&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;In this tutorial, we've explored the powerful capabilities of Mockito for mocking constructors, a crucial technique for effective unit testing, especially when dealing with complex dependencies or legacy code.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;We've seen how &lt;code&gt;mockConstruction()&lt;/code&gt; provides a flexible and modern approach to intercept and control object creation, enabling us to isolate the system under test and simulate various scenarios.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/mockito-tutorial/tree/main" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Keep learning and keep growing.&lt;/p&gt;
  
  


</content><link href="https://www.learnjavaskills.in/feeds/198026688223879006/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2025/02/mock-constructor-in-mockito.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/198026688223879006" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/198026688223879006" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2025/02/mock-constructor-in-mockito.html" rel="alternate" title="How to mock constructor in Mockito" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx53BXoQw73FwWcjVsJc40qBsW8Uj1Iw-cnk2NsXvk7TR8yPZ-mX2vWlZf6sfNwQIAk2zttCt6XW4txXn6kPgFC4ogOfvvdyRD0AY2JVpl_lSbyC3pS_VemGE4Fvr5lX2CNTzsoR6mXIWlRvhf0PIK4wV6nMtPGH2lkgIMhifEsAfRdFVtTvPYYABkxxvJ/s72-c/Constructor-Mocking.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-2781112703463837251</id><published>2025-01-26T20:48:00.000+05:30</published><updated>2025-01-26T20:48:21.004+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="Mockito"/><category scheme="http://www.blogger.com/atom/ns#" term="Unit Testing"/><title type="text">How to Mock Static Methods with Mockito: A Complete Guide | Learn Java Skills</title><content type="html">&lt;p&gt;You might need to mock the static method in your unit test in some circumstances. In this brief tutorial, we'll learn how to utilize the mockito framework to mock the behavior of a Java static method. Now, &lt;b&gt;version 3.4.0 or later supports mocking abalibity&lt;/b&gt;.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;When designing clean, maintainable, and object-oriented code, it's usual practice to avoid mock static methods because doing so could interfere with the project architecture.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;One of the foundational principles of unit testing is that in order to use it, code must be written in a specific way that makes it testable. &lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This can be accomplished by using a concept known as dependency injection, or by specifying dependencies as interfaces that can be used in place of "fake implementations" during testing.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/mockito-tutorial/tree/main" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi96FRz4xkbrkL2MB4VaNEo44Seo9hpQmczG3a5z8Jp9zeeRhWbkp1OX3WOFlARJVKQDEMPFZf6LzQ_lkOQDMELKDD4ny0VkFVp6bly566FmAMq1Uzi3xZ8bDjgaLUA_ZlpdfoyJn_hmxyg90paE2A6lzSxdxfhi7ost5H7Ltx2YUgud2IB6Kx8Ek9dLkOZ/s1600/static%20mock%20Thumbnail%202.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="How to Mock Static Methods with Mockito: A Complete Guide thumbnail image" border="0" data-original-height="720" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi96FRz4xkbrkL2MB4VaNEo44Seo9hpQmczG3a5z8Jp9zeeRhWbkp1OX3WOFlARJVKQDEMPFZf6LzQ_lkOQDMELKDD4ny0VkFVp6bly566FmAMq1Uzi3xZ8bDjgaLUA_ZlpdfoyJn_hmxyg90paE2A6lzSxdxfhi7ost5H7Ltx2YUgud2IB6Kx8Ek9dLkOZ/s1600/static%20mock%20Thumbnail%202.png"/&gt;&lt;/a&gt;&lt;/div&gt; &lt;br/&gt;

&lt;strike&gt;toc&lt;/strike&gt;
&lt;br/&gt;

&lt;h2&gt;Static Utility Class&lt;/h2&gt;
&lt;hr/&gt;

&lt;p&gt;In order to mock the static method, I developed a simple utility class with two static methods, &lt;code&gt;getTodayDay()&lt;/code&gt; and &lt;code&gt;getDayFromDate(LocalDate localDate)&lt;/code&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Both methods are used to determine the day of the week. I've written two methods to demonstrate how to mock the static method without an argument and the static method with an argument.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Utility class&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.utils;

 import in.learnjavaskills.mockitotutorial.enums.WeekDays;

 import java.time.LocalDate;
 import java.util.Calendar;

 public class Utility
 {
    public static WeekDays getTodayDay()
    {
        int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
        return WeekDays.getWeekDay(day);
    }

    public static WeekDays getDayFromDate(LocalDate localDate)
    {
        int day = localDate.getDayOfWeek().getValue();
        return switch (day) {
            case 1, 2, 3, 4, 5, 6 -&amp;gt; WeekDays.getWeekDay(day+1);
            case 7 -&amp;gt; WeekDays.SUNDAY;
            default -&amp;gt; WeekDays.UNKNOWN;
        };
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;WeekDays enum&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.enums;

 public enum WeekDays
 {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), 
    FRIDAY(6), SATURDAY(7), UNKNOWN(0);

    private int day;

    WeekDays(int day)
    {
        this.day = day;
    }

    public static WeekDays getWeekDay(int day)
    {
        for (WeekDays weekDays : WeekDays.values())
            if (weekDays.day == day)
                return weekDays;
        return WeekDays.UNKNOWN;
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;MockedStatic&amp;lt;T&amp;gt; Interface&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;The &lt;code&gt;MockedStatic&amp;lt;T&amp;gt;&lt;/code&gt; interface, which is included in the &lt;code&gt;org.mockito&lt;/code&gt; package, represents an active mock of a type's static methods. &lt;/p&gt; &lt;br/&gt;
  
&lt;p&gt;The mocking only impacts the thread on which this static mock was produced, therefore using this object from another thread is not safe. &lt;/p&gt; &lt;br/&gt;

&lt;p&gt;It is advised that you use the &lt;code&gt;ScopedMock.close()&lt;/code&gt; method to release the static mock. If the static mock is never closed, it will continue active on the current process.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Since &lt;b&gt;MockedStaticc&amp;lt;T&amp;gt;&lt;/b&gt; extends the &lt;b&gt;ScopedMock&lt;/b&gt; interface farther than the &lt;b&gt;AutoCloseable&lt;/b&gt; interface, it is advised to utilize it within the &lt;b&gt;try-with resource&lt;/b&gt;, which will be auto-closed.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&lt;/p&gt;&lt;br/&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;iframe class="BLOG_video_class" allowfullscreen="" youtube-src-id="8itp53xoa4c" width="600" height="498" src="https://www.youtube.com/embed/8itp53xoa4c"&gt;&lt;/iframe&gt;&lt;/div&gt; &lt;br/&gt;

&lt;h2&gt;Mocking the No-Argument static method&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Mock the first static method, &lt;code&gt;getTodayDay()&lt;/code&gt;, which returns an enum of WeekDays.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;To test the static mocking behavior of the &lt;u&gt;MockedStatic&amp;lt;T&amp;gt; Interface&lt;/u&gt;, I'll use the &lt;b&gt;getTodayDay()&lt;/b&gt; method without mocking to retrieve an &lt;b&gt;actual day&lt;/b&gt; of the week, and then mock it inside the &lt;b&gt;try-with resource scope to return the other day&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Once the scope of try-with resources has been fulfilled, we will call the &lt;b&gt;getTodayDay()&lt;/b&gt; method again to see if the mock has been released.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.utils;

 import in.learnjavaskills.mockitotutorial.enums.WeekDays;
 import org.junit.jupiter.api.Test;
 import org.mockito.BDDMockito;
 import org.mockito.MockedStatic;
 import org.mockito.Mockito;

 import java.time.LocalDate;

 import static org.junit.jupiter.api.Assertions.*;

 class UtilityTest
 {
    
    @Test
    void mockGetTodayDay()
    {
        // testing actual day without mocking
        assertEquals(WeekDays.TUESDAY, Utility.getTodayDay());

        try (MockedStatic&amp;lt;Utility&amp;gt; utilityMockStatic = Mockito.mockStatic(Utility.class))
        {
            // mocking the getTodayDay method to get response of the day of week as sunday instead of today day
            utilityMockStatic.when(Utility :: getTodayDay)
                    .thenReturn(WeekDays.SUNDAY);

            assertEquals(WeekDays.SUNDAY, Utility.getTodayDay());

            // verify getTodayDay method invoke at least one time
            utilityMockStatic.verify(Utility :: getTodayDay);
        }

        // testing is mock release after the try-with resource scope
        assertEquals(WeekDays.TUESDAY, Utility.getTodayDay());
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;



&lt;h2&gt;Mocking the Static Method with Arguments&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Mocking the static method with the argument is identical to mocking the static method without the argument.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Let's first grasp the &lt;code&gt;Verification Interface&lt;/code&gt; before mocking the static method with the parameter.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Verification Interface&lt;/h3&gt;

&lt;p&gt;The &lt;u&gt;Verification interface is a functional interface&lt;/u&gt; with a single abstract method, &lt;code&gt;void apply()&lt;/code&gt;, which &lt;b&gt;throws Throwable&lt;/b&gt;. It's in the &lt;code&gt;org.mockito&lt;/code&gt; package and is used to validate the static method.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The &lt;b&gt;MockedStatic&amp;lt;T&amp;gt;&lt;/b&gt; interface's &lt;code&gt;when()&lt;/code&gt; method required the Verification in the parameter and syntax given below.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; &amp;lt;S&amp;gt; OngoingStubbing&amp;lt;S&amp;gt; when(Verification verification);&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;We utilized the &lt;u&gt;method reference in the previous example of mocking the static method&lt;/u&gt;, but if you wish to mock the argument static method, you must implement the &lt;code&gt;apply()&lt;/code&gt; abstract method of the &lt;b&gt;Verification interface using the lambda expression&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;Program on Mocking the Static Method with Arguments&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.utils;

 import in.learnjavaskills.mockitotutorial.enums.WeekDays;
 import org.junit.jupiter.api.Test;
 import org.mockito.ArgumentMatchers;
 import org.mockito.BDDMockito;
 import org.mockito.MockedStatic;
 import org.mockito.Mockito;

 import java.time.LocalDate;

 import static org.junit.jupiter.api.Assertions.*;

 class UtilityTest
 {
    @Test
    void mockGetDayFromDate()
    {
        LocalDate localDate = LocalDate.now();
        // testing getDayFromDate without mocking
        assertEquals(WeekDays.TUESDAY, Utility.getDayFromDate(localDate));

        // let&amp;#39;s mock the Utility.getDayFromDate to return Sunday.
        try(MockedStatic&amp;lt;Utility&amp;gt; utilityMockStatic = Mockito.mockStatic(Utility.class))
        {
            utilityMockStatic.when(()-&amp;gt; Utility.getDayFromDate(ArgumentMatchers.any()))
                    .thenReturn(WeekDays.SUNDAY);

            assertEquals(WeekDays.SUNDAY, Utility.getDayFromDate(localDate));

            // verify mock has been called
            utilityMockStatic.verify( ()-&amp;gt; Utility.getDayFromDate(localDate));
        }

        // check if mock has been release by invoking getDayFromDate outside try-with scope
        assertEquals(WeekDays.TUESDAY, Utility.getDayFromDate(localDate));
    }
 }&lt;/code&gt;&lt;/pre&gt;

&lt;br/&gt;

&lt;h2&gt;Conclussion&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;We learnt how to mock both sorts of static methods in this brief tutorial: static methods with parameters and static methods without arguments.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;We recognize the &lt;b&gt;MockedStatic&amp;lt;T&amp;gt;&lt;/b&gt; interface, as well as the parameter of the MockedStatic&amp;lt;T&amp;gt;'s &lt;b&gt;when()&lt;/b&gt; method, i.e., the Verification Interface.&lt;/p&gt;

&lt;blockquote&gt;Always use MockedStatic&amp;lt;T&amp;gt; with the try-with resource, as it is critical to release the mocking by executing the ScopedMock interface's close() function.(alert-success)&lt;/blockquote&gt; &lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/mockito-tutorial/tree/main" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Keep learning and keep growing.&lt;/p&gt;

&lt;p align="right"&gt;&lt;a href="https://www.learnjavaskills.in/2023/11/mockito-exception-throwing.html"&gt;(getButton) #text=(Next: Mockito Exception Throwing for Unit Testing) #icon=(link) #color=(#2339bd)&lt;/a&gt;&lt;/p&gt;</content><link href="https://www.learnjavaskills.in/feeds/2781112703463837251/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/10/mock-static-methods-with-mockito.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/2781112703463837251" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/2781112703463837251" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/10/mock-static-methods-with-mockito.html" rel="alternate" title="How to Mock Static Methods with Mockito: A Complete Guide | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi96FRz4xkbrkL2MB4VaNEo44Seo9hpQmczG3a5z8Jp9zeeRhWbkp1OX3WOFlARJVKQDEMPFZf6LzQ_lkOQDMELKDD4ny0VkFVp6bly566FmAMq1Uzi3xZ8bDjgaLUA_ZlpdfoyJn_hmxyg90paE2A6lzSxdxfhi7ost5H7Ltx2YUgud2IB6Kx8Ek9dLkOZ/s72-c/static%20mock%20Thumbnail%202.png" width="72"/><thr:total>0</thr:total><georss:featurename>United States</georss:featurename><georss:point>37.09024 -95.712891</georss:point><georss:box>8.780006163821156 -130.869141 65.400473836178847 -60.556641</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-7097751169186147478</id><published>2025-01-26T20:46:00.000+05:30</published><updated>2025-01-26T20:46:55.523+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="Mockito"/><category scheme="http://www.blogger.com/atom/ns#" term="Unit Testing"/><title type="text">How to Mock Void Methods with Mockito: Everything You Need to Know | Learn Java Skills</title><content type="html">&lt;p&gt;If you're a programmer, I'm sure you've written about the void method in your application, and as a best practice for writing unit tests of your application using the concepts of &lt;b&gt;test-derived development and behavior-driven development&lt;/b&gt;, you might be wondering how we mock the void method.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;If so, you've come to the right place. In this brief article, we will learn &lt;b&gt;how to mock the void method in a Java program using&lt;/b&gt; &lt;a href="https://www.learnjavaskills.in/search/label/Mockito"&gt;mockito&lt;/a&gt;, the most popular unit testing framework.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/mockito-tutorial/tree/main" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8sInp1HFrv0Nw2MH5UBp6Nz7Q4cSzTyVwYzGl0w7hwPkauZytFpkWSLf_dk4gVOjcWt7sn43VcrfIyhLiSdwEr08ryfGM-tsd2H1eyr8wHf96VJftiddDjltBakxCMUZ7ZjVcQd0dlfe19GMa4_SjA8209lvq4RPZB0I-CO8qW6oTTeqW5wl4DRloreM2/s1600/void%20method%20mock%20thumbnail%20_2.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="How to Mock Void Methods with Mockito: Everything You Need to Know thumbnail" border="0" data-original-height="720" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8sInp1HFrv0Nw2MH5UBp6Nz7Q4cSzTyVwYzGl0w7hwPkauZytFpkWSLf_dk4gVOjcWt7sn43VcrfIyhLiSdwEr08ryfGM-tsd2H1eyr8wHf96VJftiddDjltBakxCMUZ7ZjVcQd0dlfe19GMa4_SjA8209lvq4RPZB0I-CO8qW6oTTeqW5wl4DRloreM2/s1600/void%20method%20mock%20thumbnail%20_2.png"/&gt;&lt;/a&gt;&lt;/div&gt; &lt;br/&gt;


&lt;strike&gt;toc&lt;/strike&gt; &lt;br/&gt;


&lt;h2&gt;Why is it necessary to mock the void method?&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Let's start with why we need to mock the void method. To make your test case run faster, you should avoid invoking the void function in your unit testing. To accomplish this purpose, we have a &lt;code&gt;doNothing()&lt;/code&gt; method.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The mockito's default behavior is to do nothing. You read that accurately. You might be questioning why we need &lt;code&gt;doNothing()&lt;/code&gt; in the first place.&lt;p&gt; &lt;br/&gt;
  
  &lt;p&gt;The rationale for this is so you may use the &lt;code&gt;ArgumentCaptor&lt;/code&gt; to capture the void method's arguments and check that the correct values were supplied to the void method. You may accomplish this by combining &lt;b&gt;doNoting()&lt;/b&gt; and the &lt;b&gt;&lt;a href="https://www.learnjavaskills.in/2023/10/what-is-mockito.html#What_exactly_is_ArgumentCaptor"&gt;ArgumentCaptor&lt;/a&gt;&lt;/b&gt;.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;You can also throw an exception at the time of invoking the void method to identify the behavior of your program by using the &lt;code&gt;doThrow()&lt;/code&gt; method of the mockito.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;There are numerous other actions that we can perform by mocking the void method, as we will see in the articles.&lt;/p&gt;&lt;br/&gt;


&lt;h2&gt;How to use the doNothing() method to mock the void method&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;I'm assuming you have the mockito framework properly configured in your Java application; if not, see &lt;a href="https://www.learnjavaskills.in/2023/10/what-is-mockito.html"&gt;what is Mockito&lt;/a&gt; post.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&lt;code&gt;doNothing()&lt;/code&gt; is the static method of the &lt;b&gt;Mockito&lt;/b&gt; class, which is extended by the &lt;b&gt;BDDMockito&lt;/b&gt; class.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;You may use doNothing() to instruct the void method to do nothing when invoked. &lt;b&gt;The default behavior is to do nothing&lt;/b&gt;.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Here's an example of using doNothing with the mockito to mock the void method . In the following example, we limit the DB call by mocking the void method of the &lt;code&gt;saveTransaction()&lt;/code&gt; method, which is responsible for storing the transaction data into the DB.&lt;/p&gt;&lt;br/&gt;


&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.service;

 import in.learnjavaskills.mockitotutorial.dto.TransactionDetail;
 import in.learnjavaskills.mockitotutorial.repository.TransactionRepository;
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.*;
 import org.mockito.junit.jupiter.MockitoExtension;

 import java.math.BigDecimal;

 @ExtendWith(MockitoExtension.class)
 class TransactionServiceTest
 {
    @Mock
    private TransactionRepository transactionRepository;

	@InjectMocks
    private TransactionService transactionService;

    private long transactionId = 101L;
    private TransactionDetail transactionDetail = new TransactionDetail(transactionId,
            1234_5678_9101_1213L, (byte) 23, (byte) 11, BigDecimal.TEN);

	@Test
    void doNothingWhenSaveTransactionIsInvoked()
    {
        BDDMockito.doNothing()
                .when(transactionRepository)
                .saveTransaction(transactionDetail);

        transactionService.creditCardTransaction(transactionDetail);
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;How to use the doNothing() method with ArgumentCaptor to capture the arguments of the void method&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;In our previous example, we saw how we can use the doNothing() method to mock the void method onto doing nothing, and we also learned that doNothing is the default behavior.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;As previously explained, we may capture the argument using the &lt;b&gt;&lt;a href="https://www.learnjavaskills.in/2023/10/what-is-mockito.html#What_exactly_is_ArgumentCaptor"&gt;ArgumentCaptor&lt;/a&gt;&lt;/b&gt; by utilizing the doNothing() method.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The mockito class's doNothing() method is used to &lt;b&gt;capture&lt;/b&gt; and &lt;b&gt;verify&lt;/b&gt; the parameter in the example below.&lt;/p&gt;&lt;br/&gt;


&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.service;

 import in.learnjavaskills.mockitotutorial.dto.TransactionDetail;
 import in.learnjavaskills.mockitotutorial.repository.TransactionRepository;
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.*;
 import org.mockito.junit.jupiter.MockitoExtension;

 import java.math.BigDecimal;

 @ExtendWith(MockitoExtension.class)
 class TransactionServiceTest
 {
    @Mock
    private TransactionRepository transactionRepository;

    @InjectMocks
    private TransactionService transactionService;

    private long transactionId = 101L;
    private TransactionDetail transactionDetail = new TransactionDetail(transactionId,
            1234_5678_9101_1213L, (byte) 23, (byte) 11, BigDecimal.TEN);

    @Test
    void argumentCaptorWithDoNothingOnSaveTransaction()
    {
        ArgumentCaptor&amp;lt;TransactionDetail&amp;gt; transactionDetailArgumentCaptor = 
        	ArgumentCaptor.forClass(TransactionDetail.class);

        BDDMockito.doNothing()
                .when(transactionRepository)
                .saveTransaction(transactionDetailArgumentCaptor.capture());

        transactionService.creditCardTransaction(transactionDetail);

        TransactionDetail transactionDetailArgumentCaptorValue = 
        	transactionDetailArgumentCaptor.getValue();
        Assertions.assertThat(transactionDetailArgumentCaptorValue)
        	.isNotNull();
        Assertions.assertThat(transactionDetailArgumentCaptorValue.transactionAmount())
        	.isEqualTo(transactionDetail.transactionAmount());
        Assertions.assertThat(transactionDetailArgumentCaptorValue.transactionId())
        	.isEqualTo(transactionId);
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;How to use the doThrow() method to throw an exception on the void method&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;It's best practise to test your code to check how it reacts when exceptions are thrown.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;To test how your code behaves, we may utilize the Mockito framework's &lt;code&gt;doThrow()&lt;/code&gt; function to throw an exception when methods are invoked.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The &lt;b&gt;doThrow()&lt;/b&gt; method of the &lt;b&gt;Mockito&lt;/b&gt; class, which is extended by the &lt;b&gt;BDDMockito&lt;/b&gt; class, is a static method. &lt;b&gt;When you throw an exception using the doThrow() function, a new exception instance is produced for each method call&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The following is a basic example of utilizing the doThrow() method to throw an exception while using the saveTransaction() method to persist data into the database.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.service;

 import in.learnjavaskills.mockitotutorial.dto.TransactionDetail;
 import in.learnjavaskills.mockitotutorial.repository.TransactionRepository;
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.*;
 import org.mockito.junit.jupiter.MockitoExtension;

 import java.math.BigDecimal;

 @ExtendWith(MockitoExtension.class)
 class TransactionServiceTest
 {
    @Mock
    private TransactionRepository transactionRepository;

    @InjectMocks
    private TransactionService transactionService;

    private long transactionId = 101L;
    private TransactionDetail transactionDetail = new TransactionDetail(transactionId,
            1234_5678_9101_1213L, (byte) 23, (byte) 11, BigDecimal.TEN);

    @Test
    void doThrowWhenSaveTransactionInvoke()
    {
        BDDMockito.doThrow(ClassCastException.class)
                .when(transactionRepository)
                .saveTransaction(transactionDetail);

        Assertions.assertThatThrownBy(()-&amp;gt; transactionService.creditCardTransaction(transactionDetail))
                .isExactlyInstanceOf(ClassCastException.class);
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;How to use the doCallRealMethod() method to invoke the real implementation of the method&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;We already know that the &lt;b&gt;Mockito framework's default approach when mocking the void method is to do nothing&lt;/b&gt;, but what if we actually want to execute the real implementation to test our code?&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;In that instance, we may use the &lt;code&gt;doCallRealMethod()&lt;/code&gt; function to call the real method.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The following is a simple program for invoking the void method to test the implementation using the doCallRealMethod() function.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.service;

 import in.learnjavaskills.mockitotutorial.dto.TransactionDetail;
 import in.learnjavaskills.mockitotutorial.repository.TransactionRepository;
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.*;
 import org.mockito.junit.jupiter.MockitoExtension;

 import java.math.BigDecimal;

 @ExtendWith(MockitoExtension.class)
 class TransactionServiceTest
 {
    @Mock
    private TransactionRepository transactionRepository;

    @InjectMocks
    private TransactionService transactionService;

    private long transactionId = 101L;
    private TransactionDetail transactionDetail = new TransactionDetail(transactionId,
            1234_5678_9101_1213L, (byte) 23, (byte) 11, BigDecimal.TEN);

    @Test
    void doCallRealMethodWhenSaveTransactionInvoke()
    {
        BDDMockito.doCallRealMethod()
                .when(transactionRepository)
                .saveTransaction(transactionDetail);

        transactionService.creditCardTransaction(transactionDetail);

        BDDMockito.verify(transactionRepository, Mockito.times(1))
                .saveTransaction(transactionDetail);

    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Conclussion&lt;/h2&gt;
&lt;hr&gt;
  
  &lt;p&gt;When it comes to mocking the void method, the mockito framework's default approach is to do nothing. In such scenario, utilize the &lt;b&gt;ArgumentCaptor&lt;/b&gt; with &lt;code&gt;doNothing()&lt;/code&gt; to capture the void method's parameters and check whether or not the right values were supplied to the void method.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;There may be times when you need to test if a void method throws an exception. In this case, &lt;code&gt;doThow()&lt;/code&gt; enables us to raise an exception on the void method.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;To test the void method's real implementation, we may completely rely on the &lt;code&gt;doCallRealMethod()&lt;/code&gt; method, which can partially mock the void method and enable the the method's real implementation.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/mockito-tutorial/tree/main" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Keep learning and keep growing.&lt;/p&gt;

&lt;p align="right"&gt;&lt;a href="https://www.learnjavaskills.in/2023/10/mock-static-methods-with-mockito.html"&gt;(getButton) #text=(Next: How to Mock Static Methods with Mockito) #icon=(link) #color=(#2339bd)&lt;/a&gt;&lt;/p&gt;


  </content><link href="https://www.learnjavaskills.in/feeds/7097751169186147478/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/10/mock-void-methods-with-mockito.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/7097751169186147478" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/7097751169186147478" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/10/mock-void-methods-with-mockito.html" rel="alternate" title="How to Mock Void Methods with Mockito: Everything You Need to Know | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8sInp1HFrv0Nw2MH5UBp6Nz7Q4cSzTyVwYzGl0w7hwPkauZytFpkWSLf_dk4gVOjcWt7sn43VcrfIyhLiSdwEr08ryfGM-tsd2H1eyr8wHf96VJftiddDjltBakxCMUZ7ZjVcQd0dlfe19GMa4_SjA8209lvq4RPZB0I-CO8qW6oTTeqW5wl4DRloreM2/s72-c/void%20method%20mock%20thumbnail%20_2.png" width="72"/><thr:total>0</thr:total><georss:featurename>United States</georss:featurename><georss:point>37.09024 -95.712891</georss:point><georss:box>8.780006163821156 -130.869141 65.400473836178847 -60.556641</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-8081638160856700823</id><published>2025-01-26T20:43:00.000+05:30</published><updated>2025-01-26T20:43:37.390+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="Mockito"/><category scheme="http://www.blogger.com/atom/ns#" term="Unit Testing"/><title type="text">What is Mockito? Everything You Need to Know About This Popular Java Mocking Framework | Learn Java Skills</title><content type="html">&lt;p&gt;Mockito is a Java framework that allows you to mock or clone real-world objects. &lt;/p&gt; &lt;br/&gt;

&lt;p&gt;In a nutshell, mockito is a BDD, or behavior-driven development, unit testing approach that allows you to verify the functionality of the code by mocking the objects rather than utilizing real objects.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;With the mockito framework, we can not only mock or clone the object, but also control the behavior of the function.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Such as passing dummy values as input or instructing that if a specific method has been called on the given mocked object, simply return some dummy values instead of calling that function.&lt;/p&gt; &lt;br/&gt;

  &lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/mockito-tutorial/tree/main" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;strike&gt;(toc)&lt;/strike&gt;

&lt;br/&gt;

&lt;h2&gt;Why Mockito?&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Mockito is one of the most popular mocking frameworks for Java, and it can be easily in combination with other popular unit testing frameworks in Java, such as &lt;a href="https://www.learnjavaskills.in/2023/10/ultimate-guide-to-JUnit-5-annotations.html"&gt;JUnit&lt;/a&gt; and TestNG.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Mockito, a behavior-driven programming framework, has both an annotation base and a code base for mocking.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Mockito provides a wide range of functionalities, including stubbing method calls, verifying method calls, and validating method call order.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Mockito is capable of mocking complicated dependencies like as databases and web services.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Mockito allows you to test error handling using stub method calls that return errors. This enables you to test how the code in test handles errors. This can assist you in writing more robust code.&lt;/p&gt; &lt;br/&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPLsH9R_E8to2BsXdaszbKH6k46Pugc1xuTj3NM9RRP0R8vH6lmW6t7-Y0h0Iw2kiB1uutj-sHke-lMBdKVsyBW01myn_vMSETVKqwXncwdqmFXXY3mJEGzXgWvHhX93jYX8Cf9wg4CHcx9X9CH0tfrspY1_fVDdqbXgdZOxpMlEAJh73cd_QDyyXVRg8g/s1600/Mockito%20thumbnail%20images.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="What is Mockito? Everything You Need to Know About This Popular Java Mocking Framework | Learn Java Skills thumbnail image" border="0" data-original-height="900" data-original-width="1600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPLsH9R_E8to2BsXdaszbKH6k46Pugc1xuTj3NM9RRP0R8vH6lmW6t7-Y0h0Iw2kiB1uutj-sHke-lMBdKVsyBW01myn_vMSETVKqwXncwdqmFXXY3mJEGzXgWvHhX93jYX8Cf9wg4CHcx9X9CH0tfrspY1_fVDdqbXgdZOxpMlEAJh73cd_QDyyXVRg8g/s1600/Mockito%20thumbnail%20images.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br/&gt;

&lt;h2&gt;Dependencies are required to work with the mockito framework&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Thanks to build tools including Gradle, Maven, etc., enabling behavior-driven development using the Mockito framework is now simple.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Simply include the script below in the &lt;code&gt;build.gradle&lt;/code&gt; In order to have the mockito in your application work with Gradle.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "groovy"&gt;testImplementation 'org.mockito:mockito-core:5.6.0'&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;p&gt;The code below can be used to configure the mockito if you are using the &lt;code&gt;Maven&lt;/code&gt; build tool:&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "xml"&gt; &amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.mockito&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;mockito-core&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;5.6.0&amp;lt;/version&amp;gt;
    &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
 &amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;If you are not familiar with Gradle or Maven, you may use any build tool, and mocktio library scripts can be found in the &lt;a href="https://mvnrepository.com/artifact/org.mockito/mockito-core" target="_blank" rel="nofollow"&gt;Maven central repository&lt;/a&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;As previously explained, the mockito is simple to set up with other Java unit testing frameworks like as JUnit or TestNG.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Because I'm going to use JUnit 5 with mockito, I'll need to add one additional dependency to my project, which is stated below.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "groovy"&gt;testImplementation 'org.mockito:mockito-junit-jupiter:5.6.0'&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "xml"&gt; &amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.mockito&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;mockito-junit-jupiter&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;5.6.0&amp;lt;/version&amp;gt;
    &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
 &amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;The Mockito JUnit Jupiter library script can be found in the &lt;a href="https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter" target="_blank" rel="nofollow"&gt;Maven central repository&lt;/a&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;h2&gt;Mockito annotations&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;There are several annotations used in the mockito, such as &lt;code&gt;@Mock&lt;/code&gt;, &lt;code&gt;@Spy&lt;/code&gt;, &lt;code&gt;@Captor&lt;/code&gt;, &lt;code&gt;@InjectMocks&lt;/code&gt;and &lt;code&gt;@ExtendWith(MockitoExtension.class)&lt;/code&gt;, which we will discuss subsequently.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;@Mock annotation&lt;/h3&gt;

&lt;p&gt;The @Mock annotation is used to mock or clone the object, which means you may change its behavior, such as function input, or supply some dummy output when it calls particular methods using the BDDMockito's &lt;code&gt;when()&lt;/code&gt; and &lt;code&gt;then()&lt;/code&gt; method.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The @Mock annotation is included in the &lt;code&gt;org.mockito.Mock package&lt;/code&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt;@Mock private EmployeRepository employeeRepository;&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;@Captor annotation&lt;/h3&gt;

&lt;p&gt;The @Captor annotation can be used to capture the arguments' values. The @Captor annotations are used with the BDDMocktio class's &lt;code&gt;verify()&lt;/code&gt; method.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The @Captor annotation is commonly used to validate that the same values have been supplied to the method you anticipate when unit testing by simply capturing the value using the BDDMOckito's verify method.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The &lt;code&gt;org.mockito.Captor&lt;/code&gt; package contains the @Captor annotation.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt;@Captor private ArgumentCaptor&amp;lt;String&amp;gt; name;&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;@Spy annotation&lt;/h3&gt;

&lt;P&gt;The @Spy annotation may generate a partial fake object, which means that if you're spying on a list object, you can easily add the element to the real object (rather than the mock), and you can control the behavior of the output by stubging it using the when() and then() methods of the BDDMockito class.&lt;/P&gt; &lt;br/&gt;

&lt;p&gt;The &lt;code&gt;org.mockito.Spy&lt;/code&gt; package contains the @Spy annotation.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt;@Spy private ArrayList&amp;lt;String&amp;gt; listOfEmployeeName;&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;br/&gt;

&lt;h3&gt;@InjectMocks annotation&lt;/h3&gt;

&lt;p&gt;The dependencies are injected into the object using the &lt;code&gt;@InjectMocks&lt;/code&gt; annotation. The objects associated with the annotations &lt;b&gt;@Mock&lt;/b&gt; and &lt;b&gt;@Spy&lt;/b&gt; will be injected through the @InjectMocks annotation.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Dependency injection in the mockito framework can be achieved by the use of &lt;b&gt;setters&lt;/b&gt;, &lt;b&gt;constructor bases&lt;/b&gt;, or &lt;b&gt;field&lt;/b&gt; injections, often known as property injections.
&lt;/p&gt; &lt;br/&gt;
 
&lt;p&gt;The @InjectMocks is available in the &lt;code&gt;org.mockito.InjectMocks&lt;/code&gt; package and the following snippet show how to use the @InjectMocks annotation.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt;@InjectMocks private EmployeeService employeeService;&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;@ExtendWith(MockitoExtension.class) annotation&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@ExtendWith&lt;/code&gt; annotation is a class-level JUnit 5 annotation that describes an extension model.. The &lt;code&gt;MockitoExtension.class&lt;/code&gt; is used alongside with the @ExtendWith annotation to interact with JUnit5 where mock objects are initialized and strick stubbing is handled.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The @ExtendWith annotation is comparable to the MockitoJUnitRunner annotation in JUnit 4.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;@ExtendWith is available in the &lt;code&gt;org.junit.jupiter.api.extension.ExtendWith&lt;/code&gt; package, and  MockitoExtension.class is available in the &lt;code&gt;org.mockito.junit.jupiter.MockitoExtension&lt;/code&gt; package.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The code below demonstrates how to use @ExtendWith(MockitoExtension.class).&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @ExtendWith(MockitoExtension.class)
 class EmployeeServiceTest
 {

 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Understand the classes that will be utilized for creating BDD test cases in this lecture.&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;We have a TransactionService class with the creditCardTransaction method, and we are going to generate test cases using the Mockito framework and behavior-driven development.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Before we go, let's take a short look at the classes utilized in this lesson.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;TransactionService class&lt;/h3&gt;

&lt;p&gt;We are interested about developing BDD (behavior-driven development) unit test cases for the TransactionService class using the mockito framework.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.service;

 import in.learnjavaskills.mockitotutorial.exception.TransactionException;
 import in.learnjavaskills.mockitotutorial.dto.TransactionDetail;
 import in.learnjavaskills.mockitotutorial.dto.TransactionStatus;
 import in.learnjavaskills.mockitotutorial.repository.TransactionRepository;

 import java.util.Objects;

 public class TransactionService
 {
    private TransactionRepository transactionRepository;
    public TransactionService(TransactionRepository transactionRepository)
    {
        this.transactionRepository = transactionRepository;
    }

    public TransactionStatus creditCardTransaction(TransactionDetail transactionDetail)
            throws TransactionException
    {
        if (Objects.isNull(transactionDetail))
            throw new TransactionException(&amp;quot;transactionDetails must be non null&amp;quot;);

        boolean uniqueTransactionId = transactionRepository.isUniqueTransactionId(transactionDetail.transactionId());
        System.out.println(&amp;quot;is uniqueTransactionId : &amp;quot; + uniqueTransactionId);
        if (!uniqueTransactionId)
            throw new TransactionException(&amp;quot;transaction id must be unique&amp;quot;);

        boolean isTransactionSuccess = completeTransaction(transactionDetail);
        if (isTransactionSuccess)
            return new TransactionStatus((short) 200, &amp;quot;success&amp;quot;);
        return new TransactionStatus((short) 501, &amp;quot;fail&amp;quot;);
    }

    private boolean completeTransaction(TransactionDetail transactionDetail)
    {
        if (transactionDetail.cardNumber() &amp;lt; 0)
            return false;

        transactionRepository.saveTransaction(transactionDetail);
        return true;
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;TransactionRepository class&lt;/h3&gt;

&lt;p&gt;I designed a sample repository, TransactionRepository, with several hardcoded tasks. Typically, we develop the dao layer, which is in charge of interfacing with our database to fetch or save data as needed.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;I wanted to show you how we limit the DB call while designing the unit test case since DB calls in the unit test case might be quite expensive for us.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.repository;

 import in.learnjavaskills.mockitotutorial.dto.TransactionDetail;

 public class TransactionRepository
 {
    public boolean isUniqueTransactionId(long transactionId)
    {
        return false;
    }

    public void saveTransaction(TransactionDetail transactionDetail)
    {
        System.out.println(&amp;quot;transaction saved&amp;quot;);
    }
 } &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;TransactionDetail and TransactionStatus record&lt;/h3&gt;

&lt;p&gt;The TransactionDetail and TransactionStatus records are used to accept the request and respond to it.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;I'm building an enterprise-level course to cover all topic in the mocktio. We will learn how to check the response and how requests go from one class to another by utilizing these two records, which we will examine later.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.dto;

 import java.math.BigDecimal;

 public record TransactionDetail(long transactionId, long cardNumber, byte cardExpiryYear,
                                byte cardExpiryMonth, BigDecimal transactionAmount)
 {} &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.dto;

 public record TransactionStatus(short statusCode, String message)
 {} &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;If you're new to the Java record, I recommend reading &lt;a href="https://www.learnjavaskills.in/2023/09/what-is-a-record-in-java.html"&gt;What Is a Record in Java?&lt;/a&gt;&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;TransactionException class&lt;/h3&gt;

&lt;p&gt;This session will go over the in-depth mockito framework, therefore I'd like to demonstrate how quickly we'll be able to identify whether exceptions are raised.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.exception;

 public class TransactionException extends RuntimeException
 {
    public TransactionException(String message)
    {
        super(message);
    }
 } &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Mock the behavior using the given() and willReturn() methods.&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Let's start by mock the transactionRepository class, and then we'll limit the calls to isUniqueTransactionId of the transactionRepository by utilizing the BDDMockito class's &lt;code&gt;given()&lt;/code&gt; and &lt;code&gt;willReturn()&lt;/code&gt; methods.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The transactionRepository class's isUniqueTransactionId method returns false, and that function must return true in order to test the positive case in the creditCardTransaction method. &lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Therefore, I mocked the transactionRepository class and mocked the isUniqueTransactionId method response with the value true.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;To cover the test scenario, the following code from the TransactionService class's creditCardTransaction method must be mocked..&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public boolean isUniqueTransactionId(long transactionId)
 {
     return false;
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; boolean uniqueTransactionId = transactionRepository.isUniqueTransactionId(transactionDetail.transactionId());&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;Here comes the test case, in which we mock the objects and prevent the actual object's calling by passing our own values to the function.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.service;

 import in.learnjavaskills.mockitotutorial.dto.TransactionDetail;
 import in.learnjavaskills.mockitotutorial.dto.TransactionStatus;
 import in.learnjavaskills.mockitotutorial.repository.TransactionRepository;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.ArgumentMatcher;
 import org.mockito.BDDMockito;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;

 import java.math.BigDecimal;

 import static org.junit.jupiter.api.Assertions.*;

 @ExtendWith(MockitoExtension.class)
 class TransactionServiceTest
 {
    @Mock
    private TransactionRepository transactionRepository;

    @InjectMocks
    private TransactionService transactionService;

    private long transactionId = 101L;
    private TransactionDetail transactionDetail = new TransactionDetail(transactionId,
            1234_5678_9101_1213L, (byte) 23, (byte) 11, BigDecimal.TEN);

    @Test
    void creditCardTransactionPositiveFlow()
    {
        BDDMockito.given(transactionRepository.isUniqueTransactionId(transactionId))
                .willReturn(true);

        TransactionStatus transactionStatus = transactionService.creditCardTransaction(transactionDetail);
        short statusCode = transactionStatus.statusCode();
        assertEquals(statusCode, 200);
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;The &lt;code&gt;when()&lt;/code&gt; and &lt;code&gt;thenReturn()&lt;/code&gt; methods can also be used to mock the behavior. The syntax is illustrated below. &lt;b&gt;given()&lt;/b&gt; and &lt;b&gt;willReturn()&lt;/b&gt; are frequently preferred over when() and thenReturn() since they seem more BDD.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; BDDMockito.when(transactionRepository.isUniqueTransactionId(transactionId))
	.thenReturn(true);&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;h2&gt;What exactly is ArgumentMatchers?&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;ArgumentMatchers is a class found in the &lt;code&gt;org.mockito&lt;/code&gt; package. ArgumentMatchers provide flexible verification and stubbing of mock behaviors.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;If you look closely at our previous example, when we covered mocking the behavior of the TransactionRepository's isUniqueTransactionId function, where we specifically specify the transactionId, you'll notice that&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; BDDMockito.given(transactionRepository.isUniqueTransactionId(ArgumentMatchers.anyLong()))
	.willReturn(true);&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;We may stub it instead of supplying the precise transactionId by just utilizing the ArgumentMatchers class.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 void creditCardTransactionPositiveFlow()
 {
	BDDMockito.given(transactionRepository.isUniqueTransactionId(transactionId))
    	.willReturn(true);

	TransactionStatus transactionStatus = transactionService.creditCardTransaction(transactionDetail);
	short statusCode = transactionStatus.statusCode();
    assertEquals(statusCode, 200);
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;ArgumentMatchers have several advantages&lt;/h3&gt;
  
  &lt;p&gt;1. We ensure neat, clean, and maintainable test cases by utilizing ArgumentMatchers.&lt;/p&gt; 
  &lt;p&gt;2. ArgumentMatchers enable us to apply BDD by removing hard coded values.&lt;/p&gt; &lt;br/&gt;


&lt;h2&gt;Verify the behavior with the verify() method.&lt;/h2&gt; 
&lt;hr&gt;

&lt;p&gt;The BDDMockito's &lt;code&gt;verify()&lt;/code&gt; method is used to validate behavior, such as whether a specific method is called at least once or not, and many more.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The BDDMockito class has two verify methods: the first takes two parameters, &lt;code&gt;T mock&lt;/code&gt; and &lt;code&gt;VerificationMode&lt;/code&gt;, while the second accepts just &lt;code&gt;T mock&lt;/code&gt; arguments and, by default, considers testing the mock object to be executed only once.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public static &amp;lt;T&amp;gt; T verify(T mock, VerificationMode mode) &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public static &amp;lt;T&amp;gt; T verify(T mock)&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;Let's look at an example where we can check whether a transaction is being saved into the database by seeing if the &lt;b&gt;saveTransaction()&lt;/b&gt; method of the &lt;b&gt;TransactionRepository&lt;/b&gt; class has been called once or not.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt; &lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.service;

 import in.learnjavaskills.mockitotutorial.dto.TransactionDetail;
 import in.learnjavaskills.mockitotutorial.dto.TransactionStatus;
 import in.learnjavaskills.mockitotutorial.repository.TransactionRepository;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.*;
 import org.mockito.junit.jupiter.MockitoExtension;

 import java.math.BigDecimal;

 import static org.junit.jupiter.api.Assertions.*;

 @ExtendWith(MockitoExtension.class)
 class TransactionServiceTest
 {
    @Mock
    private TransactionRepository transactionRepository;

    @InjectMocks
    private TransactionService transactionService;

    private long transactionId = 101L;
    private TransactionDetail transactionDetail = new TransactionDetail(transactionId,
            1234_5678_9101_1213L, (byte) 23, (byte) 11, BigDecimal.TEN);

    
    @Test
    void verifyTransactionSaved()
    {
        BDDMockito.given(transactionRepository.isUniqueTransactionId(ArgumentMatchers.anyLong()))
                .willReturn(true);

        transactionService.creditCardTransaction(transactionDetail);

        BDDMockito.verify(transactionRepository, Mockito.times(1))
                .saveTransaction(ArgumentMatchers.any());
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;VerificationMode&lt;/h3&gt;

&lt;p&gt;The VerificationMode is nothing except an interface that allows us to check particular behaviors, such as at least once, exactly once, never, and so on.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The &lt;code&gt;org.mockito.verification&lt;/code&gt; package contains the VerificationMode interface.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;You may use the table below to learn how to validate particular behaviors.&lt;/p&gt; &lt;br/&gt;

&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;VerificationMode&lt;/th&gt;
    &lt;th&gt;Explanation&lt;/th&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;verify(T mock, Mockito.times(1)&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;The times() method accepts one argument, i.e., wantedNumberOfInvocations of type int. This function is used to make sure certain types of behavior happen.&lt;/td&gt;
  &lt;/tr&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;verify(T mock, Mockito.never())&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;As the method name implies, never() method is used to ensure that the specific behavior does not occur at all.&lt;/td&gt;
  &lt;/tr&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;verify(T mock, Mockito.atLeastOnce())&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Use the atLeastOnce() method to ensure that the activity happened just once.&lt;/td&gt;
  &lt;/tr&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;verify(T mock, Mockito.atLeast(5)&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;The atLeast() method takes one int a parameter, minNumberOfInvocations. We may use this method to ensure that the behavior occurs at least a certain number of times.&lt;/td&gt;
  &lt;/tr&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;verify(T mock, Mockito.only())&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;The only() method may be used to check only one behavior that occurred throughout your test case.&lt;/td&gt;
  &lt;/tr&gt; 
  
    
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;verify(T mock, Mockito.atMostOnce())&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;To ensure that maximum behavior occurs just once, utilize the atMostOnce() method.&lt;/td&gt;
  &lt;/tr&gt; 
  
    
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;verify(T mock, Mockito.atMost(6))&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;The atMost() method, like the atLeast() function, needs one argument of type int, i.e. maxNumberOfInvocations, to evaluate the behavior of the maximum number of invocations.&lt;/td&gt;
  &lt;/tr&gt; 
  
&lt;/table&gt;  &lt;br/&gt;

&lt;h2&gt;What exactly is ArgumentCaptor&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;In order to confirm whether the right values are supplied to the particular method or not, we can capture the argument values using the &lt;code&gt;ArgumentCaptor&lt;/code&gt; class in the &lt;code&gt;org.mockito&lt;/code&gt; package.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;There are two approaches available to us in the mockito framework for capturing the argument: the &lt;code&gt;@Captor&lt;/code&gt; annotation or the &lt;code&gt;ArgumentCaptor.forClass(T class)&lt;/code&gt;. The second method is being used in the example below to capture the argument of the &lt;b&gt;saveTransaction()&lt;/b&gt; method.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.service;

 import in.learnjavaskills.mockitotutorial.dto.TransactionDetail;
 import in.learnjavaskills.mockitotutorial.dto.TransactionStatus;
 import in.learnjavaskills.mockitotutorial.repository.TransactionRepository;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.*;
 import org.mockito.junit.jupiter.MockitoExtension;

 import java.math.BigDecimal;

 import static org.junit.jupiter.api.Assertions.*;

 @ExtendWith(MockitoExtension.class)
 class TransactionServiceTest
 {
    @Mock
    private TransactionRepository transactionRepository;

    @InjectMocks
    private TransactionService transactionService;

    private long transactionId = 101L;
    private TransactionDetail transactionDetail = new TransactionDetail(transactionId,
            1234_5678_9101_1213L, (byte) 23, (byte) 11, BigDecimal.TEN);

    @Test
    void verifyTransactionSavedWithCorrectValues()
    {
        BDDMockito.given(transactionRepository.isUniqueTransactionId(ArgumentMatchers.anyLong()))
                .willReturn(true);

        transactionService.creditCardTransaction(transactionDetail);

        ArgumentCaptor&amp;lt;TransactionDetail&amp;gt; transactionDetailArgumentCaptor = ArgumentCaptor.forClass(TransactionDetail.class);

        BDDMockito.verify(transactionRepository)
                .saveTransaction(transactionDetailArgumentCaptor.capture());

        TransactionDetail expectedTransactionDetail = transactionDetailArgumentCaptor.getValue();
        assertEquals(transactionDetail.transactionId(), expectedTransactionDetail.transactionId());
        assertEquals(transactionDetail.transactionAmount(), expectedTransactionDetail.transactionAmount());
    }

 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;The argument passed to the specific method can be captured with the assistance of the &lt;code&gt;capture()&lt;/code&gt; method, and the values that have been captured can then be retrieved using &lt;code&gt;getValue()&lt;/code&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;Utilize the @Captor annotation to capture the values of the arguments&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.service;

 import in.learnjavaskills.mockitotutorial.dto.TransactionDetail;
 import in.learnjavaskills.mockitotutorial.dto.TransactionStatus;
 import in.learnjavaskills.mockitotutorial.repository.TransactionRepository;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.*;
 import org.mockito.junit.jupiter.MockitoExtension;

 import java.math.BigDecimal;

 import static org.junit.jupiter.api.Assertions.*;

 @ExtendWith(MockitoExtension.class)
 class TransactionServiceTest
 {
    @Mock
    private TransactionRepository transactionRepository;

    @Captor
    ArgumentCaptor&amp;lt;TransactionDetail&amp;gt; transactionDetailArgumentCaptor;

    @InjectMocks
    private TransactionService transactionService;

    private long transactionId = 101L;
    private TransactionDetail transactionDetail = new TransactionDetail(transactionId,
            1234_5678_9101_1213L, (byte) 23, (byte) 11, BigDecimal.TEN);

    @Test
    void verifyTransactionSavedWithCorrectValues()
    {
        BDDMockito.given(transactionRepository.isUniqueTransactionId(ArgumentMatchers.anyLong()))
                .willReturn(true);

        transactionService.creditCardTransaction(transactionDetail);

        BDDMockito.verify(transactionRepository)
                .saveTransaction(transactionDetailArgumentCaptor.capture());

        TransactionDetail expectedTransactionDetail = transactionDetailArgumentCaptor.getValue();
        assertEquals(transactionDetail.transactionId(), expectedTransactionDetail.transactionId());
        assertEquals(transactionDetail.transactionAmount(), expectedTransactionDetail.transactionAmount());
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;A few practical methods from the ArgumentCaptor class&lt;/h3&gt;

&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;ArgumentCaptor's method&lt;/th&gt;
    &lt;th&gt;Description&lt;/th&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;T capture()&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;The parameter values are captured using Captor(), which is required for verification.
This method internally registers a customized ArgumentMatcher implementation. The argument value is retained by this argument matcher for use when making assertions at a later time..&lt;/td&gt;
  &lt;/tr&gt;
  
   &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;T getValue()&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;The argument's captured value is returned by the getValue() method. If the verified method was called more than once, it would return the most recent captured value.&lt;/td&gt;
  &lt;/tr&gt;
  
   &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;List&amp;lt;T&amp;gt; getAllValues()&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;The getAllValues() function retrieves all of the values that have been captured when the verified method was called more than once.&lt;/td&gt;
  &lt;/tr&gt;
  
   &lt;tr&gt;
    &lt;td&gt;&lt;code&gt; &amp;lt;U, S extends U&amp;gt; ArgumentCaptor&amp;lt;U&amp;gt; forClass(Class&amp;lt;S&amp;gt; clazz)&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Create a new ArgumentCaptor.&lt;/td&gt;
  &lt;/tr&gt;
  
&lt;/table&gt;  &lt;br/&gt;

&lt;h2&gt;Verify to determine if the exception were thrown&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;If you've noticed, the creditCardTransaction() method of the TransactionService class throws a TransactionException if the method parameter is null.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; if (Objects.isNull(transactionDetail)) 
	throw new TransactionException("transactionDetails must be non null"); &lt;/code&gt;&lt;/pre&gt; &lt;br&gt;

&lt;p&gt;It's recommended to test your code to determine if it handles exceptions appropriately. &lt;/p&gt; 

&lt;blockquote&gt;To utilize Assertions.assertThatThrownBy, I used the assertj-core library. The Gradle dependencies are listed below. here. &lt;br/&gt;
  &lt;b&gt;testImplementation 'org.assertj:assertj-core:3.24.2'&lt;/b&gt; (alert-success)&lt;/blockquote&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.mockitotutorial.service;

 import in.learnjavaskills.mockitotutorial.dto.TransactionDetail;
 import in.learnjavaskills.mockitotutorial.exception.TransactionException;
 import in.learnjavaskills.mockitotutorial.repository.TransactionRepository;
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.*;
 import org.mockito.junit.jupiter.MockitoExtension;

 @ExtendWith(MockitoExtension.class)
 class TransactionServiceTest
 {
    @Mock
    private TransactionRepository transactionRepository;

    @InjectMocks
    private TransactionService transactionService;

    @Test
    void verifyExceptionThrown()
    {
        Assertions.assertThatThrownBy(()-&amp;gt; { transactionService.creditCardTransaction(null); })
                .hasMessageContaining(&amp;quot;transactionDetails must be non null&amp;quot;)
                .isExactlyInstanceOf(TransactionException.class);
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Conclussion&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;If you want to be a great developer, you must know how to test your code. In this in-depth mockito framework, we learn how to test your code by utilizing test-driven and behavior-driven development using the mockito and JUnit 5 frameworks.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;We've gone over many of the mockito framework's capabilities, such as stubbing with the &lt;b&gt;given()&lt;/b&gt; and &lt;b&gt;willReturn()&lt;/b&gt; methods to test the code's behavior. We then proceeded to the ArgumentMatchers and ArgumentCaptor.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;We covered the various methods for verifying method invocations and the verification modes; we distinguished them and knew which verification mode should be used and when.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Finally, we learn how to ensure that excaptions are handled correctly.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/mockito-tutorial/tree/main" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Keep learning and keep growing.&lt;/p&gt;

&lt;p align="right"&gt;&lt;a href="https://www.learnjavaskills.in/2023/10/mock-void-methods-with-mockito.html"&gt;(getButton) #text=(Next: How to Mock Void Methods with Mockito) #icon=(link) #color=(#2339bd)&lt;/a&gt;&lt;/p&gt;






















  
  

</content><link href="https://www.learnjavaskills.in/feeds/8081638160856700823/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/10/what-is-mockito.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/8081638160856700823" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/8081638160856700823" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/10/what-is-mockito.html" rel="alternate" title="What is Mockito? Everything You Need to Know About This Popular Java Mocking Framework | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPLsH9R_E8to2BsXdaszbKH6k46Pugc1xuTj3NM9RRP0R8vH6lmW6t7-Y0h0Iw2kiB1uutj-sHke-lMBdKVsyBW01myn_vMSETVKqwXncwdqmFXXY3mJEGzXgWvHhX93jYX8Cf9wg4CHcx9X9CH0tfrspY1_fVDdqbXgdZOxpMlEAJh73cd_QDyyXVRg8g/s72-c/Mockito%20thumbnail%20images.png" width="72"/><thr:total>0</thr:total><georss:featurename>United States</georss:featurename><georss:point>37.09024 -95.712891</georss:point><georss:box>8.780006163821156 -130.869141 65.400473836178847 -60.556641</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-6810672085963510359</id><published>2025-01-11T16:15:00.003+05:30</published><updated>2025-01-11T16:26:18.055+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><title type="text">Building Lambda Functions with Core Java: A Guide to AWS Lambda Deployment</title><content type="html">&lt;section&gt;
  &lt;p&gt;AWS Lambda is a serverless compute service offered by Amazon Web Services (AWS). It enables developers to run code without provisioning or managing servers.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;Lambda executes code in response to events and automatically manages the computing resources required by that code. This eliminates the need to worry about server maintenance, scaling, and capacity provisioning.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;In this tutorial, we will guide you through building your first AWS Lambda function using Core Java and deploying it to AWS Lambda.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/core-java-aws-lambda-function" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;
&lt;/section&gt;

&lt;strike&gt;toc&lt;/strike&gt;&lt;br/&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQDjt55BLDxMcnfFrUCNODb7okTHTZDqig2pKfdg0YYBRCs4hNQaqHJl714gNBND6pvYxXLEXkAHt_OfZR1iHogpCPKHDY07T3zC5s8LIcqoAIjYcQf4mrziNp3HdxOZmvnVcE30S_82adHLMfsNV1HvC1XK-F6VKbsgROdC-t8B1RxrdCoWP6e5UCO6pS/s1600/thumbnail-image.jpg" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Thumbnail Image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQDjt55BLDxMcnfFrUCNODb7okTHTZDqig2pKfdg0YYBRCs4hNQaqHJl714gNBND6pvYxXLEXkAHt_OfZR1iHogpCPKHDY07T3zC5s8LIcqoAIjYcQf4mrziNp3HdxOZmvnVcE30S_82adHLMfsNV1HvC1XK-F6VKbsgROdC-t8B1RxrdCoWP6e5UCO6pS/s1600/thumbnail-image.jpg"/&gt;&lt;/a&gt;&lt;/div&gt;


&lt;section&gt;
  &lt;h2&gt;Project Dependencies&lt;/h2&gt;
  &lt;hr&gt;
  &lt;p&gt;&lt;code&gt;aws-lambda-java-core&lt;/code&gt; is the essential dependency for executing your first AWS Lambda function using Core Java. While this is mandatory, you may also utilize optional dependencies when integrating with other AWS services.&lt;/p&gt;&lt;br/&gt;
  
  &lt;h3&gt;Maven&lt;/h3&gt;
  
  &lt;pre&gt;&lt;code class = "xml"&gt; &amp;#x3C;dependencies&amp;#x3E;
    &amp;#x3C;!-- Defines handler method interfaces and the context object that the runtime passes to the handler.
    If you define your own input types, this is the only library that you need. --&amp;#x3E;
    &amp;#x3C;dependency&amp;#x3E;
        &amp;#x3C;groupId&amp;#x3E;com.amazonaws&amp;#x3C;/groupId&amp;#x3E;
        &amp;#x3C;artifactId&amp;#x3E;aws-lambda-java-core&amp;#x3C;/artifactId&amp;#x3E;
        &amp;#x3C;version&amp;#x3E;1.2.3&amp;#x3C;/version&amp;#x3E;
    &amp;#x3C;/dependency&amp;#x3E;

    &amp;#x3C;!-- Optional - Input types for events from aws services that invoke Lambda functions. --&amp;#x3E;
    &amp;#x3C;dependency&amp;#x3E;
        &amp;#x3C;groupId&amp;#x3E;com.amazonaws&amp;#x3C;/groupId&amp;#x3E;
        &amp;#x3C;artifactId&amp;#x3E;aws-lambda-java-events&amp;#x3C;/artifactId&amp;#x3E;
        &amp;#x3C;version&amp;#x3E;3.14.0&amp;#x3C;/version&amp;#x3E;
    &amp;#x3C;/dependency&amp;#x3E;
 &amp;#x3C;/dependencies&amp;#x3E;&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;
  
  &lt;p&gt;Create a deployable JAR file for AWS Lambda using the Maven Shade Plugin, including all necessary built-in libraries.&lt;/p&gt;&lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "xml"&gt; &amp;#x3C;!-- building bundle jar to deploy in aws lambda --&amp;#x3E;
 &amp;#x3C;build&amp;#x3E;
    &amp;#x3C;plugins&amp;#x3E;
        &amp;#x3C;plugin&amp;#x3E;
            &amp;#x3C;groupId&amp;#x3E;org.apache.maven.plugins&amp;#x3C;/groupId&amp;#x3E;
            &amp;#x3C;artifactId&amp;#x3E;maven-shade-plugin&amp;#x3C;/artifactId&amp;#x3E;
            &amp;#x3C;version&amp;#x3E;3.3.0&amp;#x3C;/version&amp;#x3E;
            &amp;#x3C;executions&amp;#x3E;
                &amp;#x3C;execution&amp;#x3E;
                    &amp;#x3C;phase&amp;#x3E;package&amp;#x3C;/phase&amp;#x3E;
                    &amp;#x3C;goals&amp;#x3E;
                        &amp;#x3C;goal&amp;#x3E;shade&amp;#x3C;/goal&amp;#x3E;
                    &amp;#x3C;/goals&amp;#x3E;
                     &amp;#x3C;configuration&amp;#x3E;
                        &amp;#x3C;createDependencyReducedPom&amp;#x3E;false&amp;#x3C;/createDependencyReducedPom&amp;#x3E;
                    &amp;#x3C;/configuration&amp;#x3E;
                &amp;#x3C;/execution&amp;#x3E;
            &amp;#x3C;/executions&amp;#x3E;
        &amp;#x3C;/plugin&amp;#x3E;
    &amp;#x3C;/plugins&amp;#x3E;
 &amp;#x3C;/build&amp;#x3E;&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;
  
  &lt;h3&gt;Gradle&lt;/h3&gt;
  
  &lt;pre&gt;&lt;code class = "gradle"&gt; dependencies {
    // Defines handler method interfaces and the context object that the runtime passes to the handler.
    //  If you define your own input types, this is the only library that you need.
    implementation &amp;#x27;com.amazonaws:aws-lambda-java-core:1.2.3&amp;#x27;

    // Optional - Input types for events from aws services that invoke Lambda functions.
    implementation &amp;#x27;com.amazonaws:aws-lambda-java-events:3.14.0&amp;#x27;
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "gradle"&gt; // building bundle jar to deploy in aws lambda
 jar {
    from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;
  
&lt;/section&gt;

&lt;section&gt;
  &lt;h2&gt;Designing Request and Response Objects for AWS Lambda Handlers&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;This tutorial requires Java 17 or later. From Java 17 onwards, you can effectively create Java classes or records to elegantly handle request payloads (Lambda events) and responses&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;For simplicity, I will create two Java records: one for the request and another for the response, each containing relevant parameters.&lt;/p&gt;&lt;br/&gt;
  
  &lt;h3&gt;Request Payload (Lambda Event)&lt;/h3&gt;
  
  &lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills;

 public record Request(Integer id, String message) {}&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;
  
  &lt;h3&gt;Response&lt;/h3&gt;
  
  &lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills;

 public record Response(Integer statusCode, String message) {}&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;
  
&lt;/section&gt;


&lt;section&gt;
  &lt;h2&gt;Configuring Lambda Handlers in Java&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;Let's begin by creating a Java class that implements the &lt;code&gt;RequestHandler&lt;/code&gt; interface and overrides the &lt;code&gt;handleRequest()&lt;/code&gt; abstract method.&lt;/p&gt;
  
  &lt;blockquote&gt;The AWS Lambda function limits us to completing the execution of the entire function within 15 minutes, which implies we can only perform a function execution within 15 minutes.(alert-warning)&lt;/blockquote&gt;&lt;br/&gt;
  
  
  &lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills;

 import com.amazonaws.services.lambda.runtime.Context;
 import com.amazonaws.services.lambda.runtime.LambdaLogger;
 import com.amazonaws.services.lambda.runtime.RequestHandler;

 public class LambdaHandler implements RequestHandler&amp;#x3C;Request, Response&amp;#x3E; {
    /**
     * Accept a Request object containing two parameters: an integer &amp;#x27;id&amp;#x27; and a string &amp;#x27;message&amp;#x27;.
     * Log the received request and then return a 200 status response with a success message.
     */
    @Override
    public Response handleRequest(Request request, Context context) {
        LambdaLogger logger = context.getLogger();
        logger.log(&amp;#x22;Lambda handler request function invoked with request : &amp;#x22; + request.toString());
        return new Response(200, &amp;#x22;Success&amp;#x22;);
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;
  
  &lt;p&gt; &amp;#8226; &lt;code&gt;handleRequest()&lt;/code&gt; is the main method where your Lambda function's logic resides.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt; &amp;#8226; &lt;code&gt;Context&lt;/code&gt; provides information about the invocation, function, and execution environment(e.g., remaining time, log stream name, etc.).&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt; &amp;#8226; The &lt;code&gt;RequestHandler&amp;#x3C;I, O&amp;#x3E;&lt;/code&gt; interface is the cornerstone of developing AWS Lambda functions in Java.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;It serves as a contract for your Lambda function's execution logic. By implementing this interface, you tell the Lambda runtime how to handle incoming requests and generate responses. &lt;/p&gt;
  
  &lt;blockquote&gt;&lt;code&gt;&amp;#x3C;I, O&amp;#x3E;&lt;/code&gt; : These represent the input (request) and output (response) types of your Lambda function. You define these based on the specific data your function expects and produces.(alert-passed)&lt;/blockquote&gt;

&lt;/section&gt;

&lt;section&gt;
  &lt;h2&gt;Creating and Deploying Lambda Functions with the AWS Management Console&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;&lt;p&gt;Navigate to the AWS Management Console at &lt;a href="https://aws.amazon.com/console/" target="_blank" rel="nofollow"&gt;(getButton) #text=(Amazon Console) #icon=(link) #color=(#d35400)&lt;/a&gt; Sign in with your AWS credentials if you haven't already. Search for '&lt;b&gt;Lambda&lt;/b&gt;' and click on '&lt;b&gt;Create function&lt;/b&gt;'.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Select the 'Author from scratch' option, provide an appropriate name for your AWS Lambda function (e.g., 'core-java-aws-lambda-function'), and then click the 'Create function' button.&lt;/p&gt;&lt;br/&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEVATvgYv3vhF0rCejM0BTC37swvrj8ImQ7TDW6AjOcIStqSpKa8TuFN7EKoHr5dMBVCRsUIp7L8s4JiVeYPNoYcRNSrNfJTf8XuAz0yxLhBF3u02SpDU-EbsbFOWWO-GAAqsOVJSkQGXN3PaMQ78YzaON1hLrFpjEojQRsocbLc2JgkbrFpBq-vgYFJW7/s1600/01-create-function.jpg" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="core-java-aws-lambda-function" border="0" data-original-height="1058" data-original-width="2184" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEVATvgYv3vhF0rCejM0BTC37swvrj8ImQ7TDW6AjOcIStqSpKa8TuFN7EKoHr5dMBVCRsUIp7L8s4JiVeYPNoYcRNSrNfJTf8XuAz0yxLhBF3u02SpDU-EbsbFOWWO-GAAqsOVJSkQGXN3PaMQ78YzaON1hLrFpjEojQRsocbLc2JgkbrFpBq-vgYFJW7/s1600/01-create-function.jpg"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;Upon successful creation of your Lambda function, you will see the following success message.&lt;/p&gt;&lt;br/&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-OcIeSPHxlfwVymp5osAW3uMa7ZrrFZxK5t8XynluXFxM35QIFCVuo5xtlOmZLyLKHxbW4Zqf0ukDM_GpNtVg0pDIYdpKtjQEflEVXSkzuI3SwYvxisitISIt_TnZq-jB6GgSyrvYxOgp2cFxXxiOYF_SXhxN8Z_LenPnH8whMCd3AyTkQGWCFAQK3uQ-/s1600/02-lambda-function-created.jpg" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Upon successful creation of your Lambda function screen" border="0" data-original-height="1058" data-original-width="2463" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-OcIeSPHxlfwVymp5osAW3uMa7ZrrFZxK5t8XynluXFxM35QIFCVuo5xtlOmZLyLKHxbW4Zqf0ukDM_GpNtVg0pDIYdpKtjQEflEVXSkzuI3SwYvxisitISIt_TnZq-jB6GgSyrvYxOgp2cFxXxiOYF_SXhxN8Z_LenPnH8whMCd3AyTkQGWCFAQK3uQ-/s1600/02-lambda-function-created.jpg"/&gt;&lt;/a&gt;&lt;/div&gt;
  

  &lt;p&gt;Upload your bundled JAR file. Scroll down to the 'Code' section and select 'Upload from' dropdown button. Then, choose '&lt;b&gt;.zip or .jar file&lt;/b&gt;' since you have your bundled JAR.&lt;/p&gt;
  
  &lt;blockquote&gt;The AWS Lambda function allows us to upload a jar with a maximum size of 50 MB, and if the jar size is larger than or equivalent to 10 MB, we should use AWS S3.(alert-success)&lt;/blockquote&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqLFtWY-psM66usYGc0889gV3AuzUqrh44RFKRiFdMC0wOvUePcpEG_fWMJcqgsODF4hlEEu9Smzfjs0TPYbDyJkpK7itU6DCJmvbeOEWApdkR5d_UQJwKD7_jG5VUwS4Co7fm6XufUVfG34LnjXZrKgwTY6hVb2hEdIEjuntf-kDuhBFMJ0FAzI0kCOvR/s1600/04-upload-jar-step2.jpg" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Bundle jar file upload" border="0" data-original-height="464" data-original-width="2443" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqLFtWY-psM66usYGc0889gV3AuzUqrh44RFKRiFdMC0wOvUePcpEG_fWMJcqgsODF4hlEEu9Smzfjs0TPYbDyJkpK7itU6DCJmvbeOEWApdkR5d_UQJwKD7_jG5VUwS4Co7fm6XufUVfG34LnjXZrKgwTY6hVb2hEdIEjuntf-kDuhBFMJ0FAzI0kCOvR/s1600/04-upload-jar-step2.jpg"/&gt;&lt;/a&gt;&lt;/div&gt;
  

  &lt;p&gt;An upload window will appear. Click the '&lt;b&gt;Upload&lt;/b&gt;' button (as shown in the screenshot below) and select your bundled JAR file from your local machine. Finally, click the '&lt;b&gt;Save&lt;/b&gt;' button.&lt;/p&gt;&lt;br/&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbaf6Cz18RJgdp5jtd8WaoPXw_qKYeh9tkBgVq6wdWX8jlRXc9xfrUgdcsLh4zpnf7amJOc74X2NUBrD05YPFLu4PPSjxK9PzFF52RV69IH2GEkhCYLiXycIjEJiBZq4_zmz56WfEh43dsDUZMcea9c8ymrvIKjbtXIO7JiEINnYhhdwtCIkevcUwOByuY/s1600/06-upload-jar-step4-jar-uploaded.jpg" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="upload jar file" border="0" data-original-height="711" data-original-width="1599" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbaf6Cz18RJgdp5jtd8WaoPXw_qKYeh9tkBgVq6wdWX8jlRXc9xfrUgdcsLh4zpnf7amJOc74X2NUBrD05YPFLu4PPSjxK9PzFF52RV69IH2GEkhCYLiXycIjEJiBZq4_zmz56WfEh43dsDUZMcea9c8ymrvIKjbtXIO7JiEINnYhhdwtCIkevcUwOByuY/s1600/06-upload-jar-step4-jar-uploaded.jpg"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;Next, let's configure the Runtime Settings. Here, you can update the Java version and specify the request handler method path. Click the 'Edit' button to proceed.&lt;/p&gt;&lt;br/&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvEVPZAma8lWlxrO0OtZG3tSkhfEzh69Hq8MMc6sxLk8Oyl2VieJjMPUkAx-Jq0nN3lCXjc0TWMzEyt8NoTpJU9HjiF1GULQlWuKDfis3RSPqD09asMChVzVxVz2_JXKdRQQ9QrfepMEEGJ7NqT9Vd_6CtWhZ8jSGc_izR0Lh3d9YHIYJfAbS-MGBQ_R4C/s1600/07-runtime-configuration-step1.jpg" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="configure runtime settings" border="0" data-original-height="363" data-original-width="2447" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvEVPZAma8lWlxrO0OtZG3tSkhfEzh69Hq8MMc6sxLk8Oyl2VieJjMPUkAx-Jq0nN3lCXjc0TWMzEyt8NoTpJU9HjiF1GULQlWuKDfis3RSPqD09asMChVzVxVz2_JXKdRQQ9QrfepMEEGJ7NqT9Vd_6CtWhZ8jSGc_izR0Lh3d9YHIYJfAbS-MGBQ_R4C/s1600/07-runtime-configuration-step1.jpg"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  
  &lt;p&gt;In the 'Handler' field, specify &lt;code&gt;in.learnjavaskills.LambdaHandler::handleRequest&lt;/code&gt;. You must update this value to match your package, class name, and method name (e.g., &lt;code&gt;your.package.ClassName::yourMethod&lt;/code&gt;). You can also configure the Java runtime version, which is set to Java 21 in this example.&lt;/p&gt;&lt;br/&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcvbLfyc-cz1L7VER2g02xoGEeqcptsospZmw5S-vteNqlCXrMrpoNaA6D8eMwQ-zNNiIWKRvy-NfHEkFwQhHtvRVX7Q2D2TnJK14gkv_e2loqgnxcjarLyWt5E8nVowuzUmxSk8DTlSwnuvDyEiF6dNntcia41KduTf0L8SVn6a4DIBJT-UHIpXgWTAhz/s1600/08-runtime-configuration-step2-handler-package.jpg" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="handler and java runtime configuration" border="0" data-original-height="1135" data-original-width="2447" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcvbLfyc-cz1L7VER2g02xoGEeqcptsospZmw5S-vteNqlCXrMrpoNaA6D8eMwQ-zNNiIWKRvy-NfHEkFwQhHtvRVX7Q2D2TnJK14gkv_e2loqgnxcjarLyWt5E8nVowuzUmxSk8DTlSwnuvDyEiF6dNntcia41KduTf0L8SVn6a4DIBJT-UHIpXgWTAhz/s1600/08-runtime-configuration-step2-handler-package.jpg"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;Finally, test your Lambda function. Navigate to the &lt;code&gt;Test&lt;/code&gt; section and create a new &lt;b&gt;test event&lt;/b&gt;. Give it a name (e.g., "test-function") and provide the Event JSON.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;This JSON represents the request payload for your function. In our example, we created a &lt;code&gt;Request&lt;/code&gt; Java record with an integer '&lt;b&gt;id&lt;/b&gt;' and a string '&lt;b&gt;message&lt;/b&gt;'.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;Therefore, the Event JSON should include these two parameters, which your Lambda function expects to receive."&lt;/p&gt;&lt;br/&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsrelYcnuwFfICWC8v9MvqWbplbzmp4byfnIXYxRA8WQsTp1sUO_MOG-oZ4Kk6XZSTf4k7mp9RdJH0zmA_b1BQbR7URcqiT3dZhNYHHQRHgMGI4yQ2C3rSlnb2_0N30sfx150rMtKkO47Et0g2N2DDDi858R6I_fEvckTbLqUYNBZbxj6wtMv7HSrk_sDt/s1600/09-testing.jpg" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="create test event for lambda function" border="0" data-original-height="1214" data-original-width="2470" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsrelYcnuwFfICWC8v9MvqWbplbzmp4byfnIXYxRA8WQsTp1sUO_MOG-oZ4Kk6XZSTf4k7mp9RdJH0zmA_b1BQbR7URcqiT3dZhNYHHQRHgMGI4yQ2C3rSlnb2_0N30sfx150rMtKkO47Et0g2N2DDDi858R6I_fEvckTbLqUYNBZbxj6wtMv7HSrk_sDt/s1600/09-testing.jpg"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;Upon clicking the '&lt;b&gt;Test&lt;/b&gt;' button, you will receive the response from your Lambda function. In this case, you should see a 200 status code and a 'success' message.&lt;/p&gt;&lt;br/&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7A6NzHsYzspVu-5WmX3wR7Yby8t8nKy7bNc-zp_Olg_QbYlk2qC_wAGDNZiQoHXtyWEqw_ACTn8t40I0kXLEQzcdNwPn-cP9n9me-U1qa6yz95v-sYeenVb0IsKW9cYYgI3Aka_c5wIarC_Jdj8gWpWLTDQDOZWluDwWNWYkfOoKncStW17SFIdVGeUt_/s1600/10-test-sucess-response.jpg" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="success response from aws lambda function" border="0" data-original-height="1204" data-original-width="2447" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7A6NzHsYzspVu-5WmX3wR7Yby8t8nKy7bNc-zp_Olg_QbYlk2qC_wAGDNZiQoHXtyWEqw_ACTn8t40I0kXLEQzcdNwPn-cP9n9me-U1qa6yz95v-sYeenVb0IsKW9cYYgI3Aka_c5wIarC_Jdj8gWpWLTDQDOZWluDwWNWYkfOoKncStW17SFIdVGeUt_/s1600/10-test-sucess-response.jpg"/&gt;&lt;/a&gt;&lt;/div&gt;
  
&lt;/section&gt;

&lt;blockquote&gt;Once you've finished your lab exercise, remember to delete your AWS lambda function, layer, and API Gateway.(alert-error)&lt;/blockquote&gt;&lt;br/&gt;


&lt;section&gt;
  &lt;h2&gt;Conclussion&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;This tutorial demonstrates how to develop AWS Lambda functions using Core Java and deploy them to the AWS Lambda service. To minimize dependencies, leverage the Lambda Layer functionality to deploy a command library.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;AWS Lambda functions have a 15-minute maximum execution time limit.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;While direct CPU size configuration is not possible, increasing the allocated memory will proportionally increase the available CPU power&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;Learn how to build serverless functions with &lt;a href="https://www.learnjavaskills.in/2023/09/spring-cloud-function-deploys-in-aws-lambda-and-triggers-using-the-api-gateway.html"&gt;(getButton) #text=(Spring Cloud Function) #icon=(link) #color=(#35a576)&lt;/a&gt;, seamlessly deploy them on AWS Lambda, and create RESTful APIs using AWS API Gateway in this comprehensive blog.&lt;/p&gt;&lt;br/&gt;
    
   &lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/core-java-aws-lambda-function" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;
  
&lt;/section&gt;</content><link href="https://www.learnjavaskills.in/feeds/6810672085963510359/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2025/01/core-java-aws-lambda-function.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/6810672085963510359" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/6810672085963510359" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2025/01/core-java-aws-lambda-function.html" rel="alternate" title="Building Lambda Functions with Core Java: A Guide to AWS Lambda Deployment" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQDjt55BLDxMcnfFrUCNODb7okTHTZDqig2pKfdg0YYBRCs4hNQaqHJl714gNBND6pvYxXLEXkAHt_OfZR1iHogpCPKHDY07T3zC5s8LIcqoAIjYcQf4mrziNp3HdxOZmvnVcE30S_82adHLMfsNV1HvC1XK-F6VKbsgROdC-t8B1RxrdCoWP6e5UCO6pS/s72-c/thumbnail-image.jpg" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-2917200440041767953</id><published>2025-01-04T16:01:00.000+05:30</published><updated>2025-01-04T16:01:19.045+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="Spring Data JPA"/><title type="text">How to use Pagination and Sorting with Spring Data JPA | Learn Java Skills</title><content type="html">

&lt;div&gt;
  &lt;p&gt;When retrieving huge amounts of data from a SQL database, the lazy operation is preferable over the eager operation.&lt;/p&gt; &lt;br/&gt;

  
  &lt;p&gt;You may be required to retrieve a huge amount of data from a SQL database and give it back to the client, and you may be wondering what the performance cost would be if you query a SQL database to retrieve all the data at once.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Yes, you are correct; it is not best practice to query a significant amount of the database to find all the data at once. You may be wondering, what is the ideal approach if the business requirement is to send the entire table of data?&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;In such scenarios, you have to integrate the concept of pagination or sorting into your application, because even if you return a significant amount of data to your client, it is assumed that your service's users will not use all of the data.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Consider the following e-commerce website: An e-commerce website's backend may have a large quantity of data, yet it only displays a small bit of data at a time. So, if you wish to see additional products, then only they will bring up the next set of products on your screen.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;This is what pagination is all about. Fetch the data on demand.&lt;/p&gt; &lt;br/&gt;
  
  &lt;strike&gt;toc&lt;/strike&gt;
  
&lt;/div&gt;

&lt;!-- thumbnail image --&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcKt-7NAckDJ-SyjDelIIorZNLyNnnRH7CYFVDpAad_W8tgNwC6Vr5WO12-9X6E1mmSahfdZDZpjWsSR8IfO8GcZAi_sk1rA06Pzp6V6TBaFcrcNwNou9wNfV3TIQIiUUtZVUL0K_04WQ20XV1oNNLEpI_JMLp-On_ONDlw_Lc7jUzh2ncZRDKGjsam8O6/s1600/Pagination%20new%20thumbnail.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Pagination and Sorting with Spring Data JPA thumbnail image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcKt-7NAckDJ-SyjDelIIorZNLyNnnRH7CYFVDpAad_W8tgNwC6Vr5WO12-9X6E1mmSahfdZDZpjWsSR8IfO8GcZAi_sk1rA06Pzp6V6TBaFcrcNwNou9wNfV3TIQIiUUtZVUL0K_04WQ20XV1oNNLEpI_JMLp-On_ONDlw_Lc7jUzh2ncZRDKGjsam8O6/s1600/Pagination%20new%20thumbnail.png"/&gt;&lt;/a&gt;&lt;/div&gt;


&lt;div&gt;
  &lt;!--1. Dependencies --&gt;
  &lt;h2&gt;Dependencies&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;To use the Spring data JPA in your Spring Boot application, you only need two dependencies. The first is &lt;b&gt;spring-boot-starter-data-jpa&lt;/b&gt;, and the second one is about the database you are using. I've utilized &lt;b&gt;MySql&lt;/b&gt; throughout this lesson.&lt;/p&gt;
  
  &lt;br/&gt;
  
  &lt;p&gt;&lt;a href="https://www.learnjavaskills.in/2020/10/Spring-Data-JPA.html"&gt;Here&lt;/a&gt; are more details on Spring Data JPA.&lt;/p&gt;
  
  &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "xml:brush"&gt; &amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter-data-jpa&amp;lt;/artifactId&amp;gt;
 &amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  
  &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "xml:brush"&gt; &amp;lt;dependency&amp;gt;
	&amp;lt;groupId&amp;gt;com.mysql&amp;lt;/groupId&amp;gt;
	&amp;lt;artifactId&amp;gt;mysql-connector-j&amp;lt;/artifactId&amp;gt;
	&amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
 &amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  
&lt;/div&gt;  

&lt;br/&gt;

&lt;div&gt;
  &lt;!-- 2. Create an entity as well as the repository. --&gt;
  &lt;h2&gt;Create an entity as well as the repository.&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;I'm expecting you to have finished configuring your database in your spring boot application. If not, I recommend reading &lt;a href="https://www.learnjavaskills.in/2020/10/how-to-connect-mysql-database-in-spring.html"&gt;this&lt;/a&gt; page to learn how to configure the MySQL database in the spring boot application.&lt;/p&gt;
  
  &lt;br/&gt;
  
  &lt;p&gt;In my MySQL database, I have a table called employee that I'll use to demonstrate pagination and sorting.&lt;/p&gt;
  &lt;br/&gt;
  
  &lt;p&gt;I'll make an entity and a repository for this table.&lt;/p&gt; &lt;br/&gt;
  
  &lt;h3&gt;Employee Entity&lt;/h3&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; package in.learnjavaskills.paginationandsorting.entity;

 import jakarta.persistence.*;

 import java.util.Objects;

 @Entity
 @Table(name = &amp;quot;employee&amp;quot;)
 public class Employee
 {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name =&amp;quot;id&amp;quot;)
    private Long id;

    @Column(name = &amp;quot;first_name&amp;quot;, nullable = false)
    private String firstName;

    @Column(name = &amp;quot;last_name&amp;quot;)
    private String lastName;

    @Column(name = &amp;quot;address&amp;quot;)
    private String address;
    // getter and setter, constructor, equal and hashcode, tostring
 }&lt;/code&gt;&lt;/pre&gt;
  
  &lt;br/&gt;
  
  &lt;h3&gt;Employee Repository&lt;/h3&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; package in.learnjavaskills.paginationandsorting.repository;

 import in.learnjavaskills.paginationandsorting.entity.Employee;
 import org.springframework.data.repository.PagingAndSortingRepository;

 public interface EmployeeRepository extends PagingAndSortingRepository&amp;lt;Employee, Long&amp;gt;
 {} &lt;/code&gt;&lt;/pre&gt;
  &lt;br/&gt;
  
  &lt;p&gt;Here I used the &lt;b&gt;PagingAndSortingRepository&lt;/b&gt; interface; you can also use the &lt;b&gt;JpaRepository&lt;/b&gt; interface.&lt;/p&gt; &lt;br/&gt;
  &lt;p&gt;The &lt;u&gt;JpaRepository&lt;/u&gt;  interface extends the &lt;b&gt;ListPagingAndSortingRepository&lt;/b&gt;  interface and the &lt;u&gt;ListPagingAndSortingRepository&lt;/u&gt; interface extends the &lt;u&gt;PagingAndSortingRepository&lt;/u&gt;  interface.&lt;/p&gt;
  
&lt;/div&gt;

&lt;br/&gt;

&lt;div&gt;
  &lt;!--3. Pagination with the spring data JPA in the spring boot --&gt;
  &lt;h2&gt;Pagination with the spring data JPA in the spring boot&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;Pagination is utilized when we wish to fetch all the data from the database, as was covered earlier in this lesson. We fetch the data chunk by chunk using the pagination idea to enhance performance.&lt;/p&gt; &lt;br/&gt;
  
  &lt;h3&gt;Pageable Interface&lt;/h3&gt;
  
  &lt;p&gt;The pageable is an interface that offers a number of pagination-related operations.Some of the most widely used methods are as follows:&lt;/p&gt; &lt;br/&gt;
  
  
  &lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;Method's&lt;/th&gt;
    &lt;th&gt;Description&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;int getPageSize();&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Use the getPageSize method to determine how many pages there are in total&lt;/td&gt;
    
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;int getPageNumber();&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;You can obtain the current page by using the getPageNumber method.&lt;/td&gt;
  &lt;/tr&gt;
    &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;Sort getSort();&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;The getSort method is used for finding the Sort class.&lt;/td&gt;
  &lt;/tr&gt;
    &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;Pageable next();&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Use the next method to move to the next Pageable.&lt;/td&gt;
  &lt;/tr&gt;
    &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;Pageable previousOrFirst();&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Use the previousOrFirst function to go to the previous or first Pageable.&lt;/td&gt;
  &lt;/tr&gt;
    &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;Pageable first();&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;The first method is availabe to jump to the first Pageable.&lt;/td&gt;
  &lt;/tr&gt;
    &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;boolean hasPrevious();&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;To determine whether the previous pageable is available or not, use the hasPrevious method.&lt;/td&gt;
  &lt;/tr&gt;
    &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;Pageable withPage(int pageNumber)&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;By specifying the page number using the withPage method, you can expect the exact pageable.&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
  &lt;br/&gt;
  
  
  &lt;h3&gt;How do I create an instance of pageable?&lt;/h3&gt;
  
  &lt;p&gt;To build a pageable instance, we can use the static methods of the PageRequest class.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Let's execute our first pagination program to better understand its operation.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;In this example, I'll use the &lt;u&gt;PagingAndSortingRepository interface's findAll method&lt;/u&gt; to retrieve the whole set of records from the employee table.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; @Test
 void findAllData()
 {
   Pageable pageable = PageRequest.of(0, 1);
   Page&amp;lt;Employee&amp;gt; page = employeeRepository.findAll(pageable);
   System.out.println(&amp;quot;total pages : &amp;quot; + page.getTotalPages());
   if (page.hasContent())
   {
 	 List&amp;lt;Employee&amp;gt; employeeList = page.getContent();
 	 if (Objects.nonNull(employeeList) &amp;amp;&amp;amp; !employeeList.isEmpty())
 	   employeeList.forEach(System.out :: println);
   }
 }&lt;/code&gt;&lt;/pre&gt;
  
  &lt;br/&gt;
  &lt;p&gt;As you can see from the example above, we have a repository instance called employeeRepository, and we performed the pagination using the &lt;u&gt;findAll&lt;/u&gt; method , which accepts a pageable object.&lt;/p&gt; &lt;br/&gt;
  
  &lt;blockquote&gt;PageRequest.of() method takes two arguments, which are as follows: &lt;br/&gt;
    &lt;b&gt;pageNumber:&lt;/b&gt; This is a parameter of the int type, and as its name suggests, you must supply it with the page number for which you want to retrieve page data. &lt;br/&gt;
    &lt;b&gt;pageSize:&lt;/b&gt; This option, which is of the int type, asks you to specify how many records to show each page.
    &lt;p&gt;To create an instance of the Pageable interface, use the PageRequest.of() function.&lt;/p&gt;(alert-passed)&lt;/blockquote&gt;&lt;br/&gt;
  
&lt;/div&gt;  

&lt;br/&gt;

&lt;div&gt;
  &lt;!-- 4. Sorting with spring data JPA in the spring boot --&gt;
  &lt;h2&gt;Sorting with spring data JPA in the spring boot&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;The Sort class, which is part of the &lt;b&gt;org.springframework.data.domain&lt;/b&gt; package, can be used to sort the record.&lt;/p&gt;
  
  &lt;br/&gt;
  
  &lt;p&gt;You can sort your results using any of the numerous overloaded &lt;b&gt;Sort.by()&lt;/b&gt; methods that are available, depending on your needs.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;As you can see, I sorted the outcome by the employee's first name in &lt;u&gt;ascending order using the sort.by() method&lt;/u&gt;.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; @Test
 void sortData()
 {
   Sort sortByFirstNameInAscOrder = Sort.by(Sort.Direction.ASC, &amp;quot;firstName&amp;quot;);
   Pageable pageable = PageRequest.of(0, 4, sortByFirstNameInAscOrder);
   Page&amp;lt;Employee&amp;gt; page = employeeRepository.findAll(pageable);
   System.out.println(&amp;quot;total pages : &amp;quot; + page.getTotalPages());
   if (page.hasContent())
   {
     List&amp;lt;Employee&amp;gt; employeeList = page.getContent();
     if (Objects.nonNull(employeeList) &amp;amp;&amp;amp; !employeeList.isEmpty())
       employeeList.forEach(System.out :: println);
   }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;br/&gt;
  
  &lt;blockquote&gt;Here, I used the Sort by(Direction direction, String... properties)  method with the following two arguments: &lt;br/&gt;
    &lt;b&gt;Direction:&lt;/b&gt; The Sort class contains an enum called "Direction." We can use it to specify the sort order we desire, such as ASC for ascending and DESC for descending. &lt;br/&gt;
    &lt;b&gt;Arrays of String:&lt;/b&gt; which accepts the field's name for sorting; in this case, we used the employee's first name.(alert-success)&lt;/blockquote&gt;
  
  &lt;blockquote&gt;Sort by(Direction direction, String... properties)&lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt;
  
  &lt;br/&gt;
  
  &lt;blockquote&gt;Is sorting the direction possible solely using the Direction enum? In addition, you may adjust the sorting direction by using the Sort class's ascending() or descending() method.(alert-passed)&lt;/blockquote&gt;
    &lt;blockquote&gt;Sort sortByFirstNameInAscOrder = Sort.by("firstName").ascending(); &lt;br/&gt;Sort sortByFirstNameInDesOrder = Sort.by("firstName").descending();&lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt;
  
  &lt;h3&gt;Is there the ideal way to use sorting without utilizing pagination?&lt;/h3&gt;
  
  &lt;p&gt;We saw how to sort the result with pagination in the previous example, but are we able to sort the result without using pagination in our application?&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Yes, you are correct; we can sort the result in spring data JPA without requiring pagination. We will have the similar experience in the following session.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; @Test
 void sortDataWithoutPagination()
 {
   Sort sortByFirstNameInDesOrder = Sort.by(&amp;quot;firstName&amp;quot;).descending();
   Pageable pageable = PageRequest.of(0, 4, sortByFirstNameInDesOrder);
   List&amp;lt;Employee&amp;gt; employeeList = (List&amp;lt;Employee&amp;gt;) employeeRepository.findAll(sortByFirstNameInDesOrder);

   if (Objects.nonNull(employeeList) &amp;amp;&amp;amp; !employeeList.isEmpty())
	 employeeList.forEach(System.out :: println);
 }&lt;/code&gt;&lt;/pre&gt;
  
&lt;div&gt;  
  
 &lt;br/&gt;
  
 &lt;div&gt;
   &lt;!-- 5. How to use pagination and sorting on the user-defined query --&gt;
   &lt;h2&gt;How to use pagination and sorting on the user-defined query&lt;/h2&gt;
   &lt;hr&gt;
   
   &lt;p&gt;We had previously used the &lt;u&gt;pagination and sorting&lt;/u&gt; on the Spring data JPA predefine method, which were provided out of the box.&lt;/p&gt; &lt;br/&gt;
   
   &lt;p&gt;If you've come this far, you must have wondered about it. It's OK; we can utilize the pagination and sorting on the Spring data JPA's interface function, but what if we need to execute the same pagination and sorting on our own query?&lt;/p&gt; &lt;br/&gt;
   
   &lt;p&gt;The following section will walk us through how we will be able to do pagination and sorting on the user-defined query.&lt;/p&gt;
   &lt;br/&gt;
   
   &lt;p&gt;To allow pagination in your custom query, accept the &lt;u&gt;pageable interface&lt;/u&gt; in the abstract method of your repository.&lt;/p&gt;
   &lt;br/&gt;
   
   &lt;p&gt;I'm implementing the JPQL query right here in the employee repository. The native query will also work for both queries, or you are able to follow to the exact same process.&lt;/p&gt; &lt;br/&gt;
   
   &lt;p&gt;You can also learn how to use the DTO project in spring boot with spring data JPA by &lt;a href="https://www.learnjavaskills.in/2023/08/spring-data-jpa-dto-projections.html"&gt;clicking here&lt;/a&gt;.&lt;/p&gt;&lt;br/&gt;
   
   &lt;pre&gt;&lt;code class = "java:brush"&gt; package in.learnjavaskills.paginationandsorting.repository;

 import in.learnjavaskills.paginationandsorting.entity.Employee;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.PagingAndSortingRepository;

 public interface EmployeeRepository extends PagingAndSortingRepository&amp;lt;Employee, Long&amp;gt;
 {
    @Query(&amp;quot;from Employee&amp;quot;)
    Page&amp;lt;Employee&amp;gt; findAllEmployee(Pageable pageable);
 }&lt;/code&gt;&lt;/pre&gt;
   
   &lt;br/&gt;
   
   &lt;p&gt;Once you've finished declaring the abstract method in the repository layer with the pageable interface, you may utilize it exactly as we did earlier in this article in the service layer.&lt;/p&gt; &lt;br/&gt;
   
   &lt;pre&gt;&lt;code class = "java:brush"&gt; @Test
 void paginationOnUserDefineMethod()
 {
   Sort sortByFirstNameInDesOrder = Sort.by(&amp;quot;firstName&amp;quot;).descending();
   Pageable pageable = PageRequest.of(0, 4, sortByFirstNameInDesOrder);
   Page&amp;lt;Employee&amp;gt; page = employeeRepository.findAllEmployee(pageable);
   System.out.println(&amp;quot;total pages : &amp;quot; + page.getTotalPages());
   if (page.hasContent())
   {
     List&amp;lt;Employee&amp;gt; employeeList = page.getContent();
     if (Objects.nonNull(employeeList) &amp;amp;&amp;amp; !employeeList.isEmpty())
       employeeList.forEach(System.out :: println);
   }
 }&lt;/code&gt;&lt;/pre&gt;

  &lt;/div&gt; 
  
  &lt;br/&gt;
  
  &lt;div&gt;
    &lt;!-- 6. What exactly is the Slice interface? In Spring Data JPA pagination, how do I use the Slice interface? --&gt;
    &lt;h2&gt;What exactly is the Slice interface? In Spring Data JPA pagination, how do I use the Slice interface?&lt;/h2&gt;
    &lt;hr&gt;
    
    &lt;p&gt;Slice is an interface in the &lt;b&gt;org.springframework.data.domain&lt;/b&gt; package that allows us to get a single slice of data. We've learnt that if we want to use pagination, we can use the page interface as the return type of the result, but you can also use the slice interface instead.&lt;/p&gt;&lt;br/&gt;
    
    &lt;p&gt;In the Page interface, we must explicitly specify the page number to retrieve the data, whereas in the Slice interface, we simply utilize the &lt;b&gt;hasNext()&lt;/b&gt; method to detect whether the next batch is available or not.&lt;/p&gt;&lt;br/&gt;
    
    &lt;p&gt;You can access the next batch of data using the &lt;b&gt;nextPageable()&lt;/b&gt; method once the next batch is available.&lt;/p&gt;&lt;br/&gt;
    
    &lt;p&gt;In the following part, we'll look at how the slice interface interacts with Pageable.&lt;/p&gt;&lt;br/&gt;
    
    &lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.paginationandsorting.repository;

 import in.learnjavaskills.paginationandsorting.entity.Employee;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.domain.Slice;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.PagingAndSortingRepository;

 public interface EmployeeRepository extends PagingAndSortingRepository&amp;lt;Employee, Long&amp;gt;
 {
    @Query(&amp;quot;from Employee&amp;quot;)
    Slice&amp;lt;Employee&amp;gt; findAllEmployee(Pageable pageable);
 }&lt;/code&gt;&lt;/pre&gt;
    &lt;br/&gt;
    
    &lt;p&gt;Let's look at how the slice interface can be used in the service layer. As previously explained, we must utilize the &lt;u&gt;hasNext()&lt;/u&gt; method to verify whether the next batch is accessible and then use &lt;u&gt;nextPageable()&lt;/u&gt; to move on to the next batch.&lt;/p&gt; &lt;br/&gt;
    
    &lt;pre&gt;&lt;code class = "java"&gt; @Test
 void paginationOnUsingTheSlice()
 {
  Sort sortByFirstNameInDesOrder = Sort.by(&amp;quot;firstName&amp;quot;).descending();
  Pageable pageable = PageRequest.of(0, 1, sortByFirstNameInDesOrder);
  Slice&amp;lt;Employee&amp;gt; slice = employeeRepository.findAllEmployee(pageable);

  if (slice.hasContent())
  {
    List&amp;lt;Employee&amp;gt; employeeList = slice.getContent();
    if (Objects.nonNull(employeeList) &amp;amp;&amp;amp; !employeeList.isEmpty())
      employeeList.forEach(System.out :: println);

    while (slice.hasNext())
    {
      slice = employeeRepository.findAllEmployee(slice.nextPageable());
      employeeList = slice.getContent();
      if (Objects.nonNull(employeeList) &amp;amp;&amp;amp; !employeeList.isEmpty())
        employeeList.forEach(System.out :: println);
    }
  }
 }&lt;/code&gt;&lt;/pre&gt;
    &lt;br/&gt;
    
    &lt;blockquote&gt;Slice is an interface in the &lt;b&gt;org.springframework.data.domain&lt;/b&gt; package that allows us to get a single slice of data. &lt;br/&gt;
      The &lt;b&gt;hasContent()&lt;/b&gt; method determines whether or not the batch of data is empty. &lt;br/&gt;
      The &lt;b&gt;hasNext()&lt;/b&gt; method is used to see whether the next bacth is available. &lt;br/&gt;
      The &lt;b&gt;nextPageable()&lt;/b&gt; method is used to get the next pageable interface instance in order to get the next batch data.(alert-passed)&lt;/blockquote&gt;

    &lt;br/&gt;
  &lt;/div&gt; 
  
  &lt;br/&gt;
  
  &lt;div&gt;
    &lt;!-- 7. What is the key difference between the page interface and the slice interface? --&gt;
    &lt;h2&gt;What is the key difference between the page interface and the slice interface?&lt;/h2&gt;
    &lt;hr&gt;
    
    &lt;p&gt;The &lt;b&gt;org.springframework.data.domain&lt;/b&gt; package contains both the &lt;u&gt;page&lt;/u&gt; interface and the &lt;u&gt;slice&lt;/u&gt; interface.&lt;/p&gt; &lt;br/&gt;
    
    &lt;p&gt;The &lt;u&gt;page&lt;/u&gt; interface extends the &lt;u&gt;slice&lt;/u&gt; interface, which means that it has all of the capabilities of the slice interface, whereas the slice interface extends the &lt;b&gt;streamable&lt;/b&gt; interface.&lt;/p&gt;
    
    &lt;blockquote&gt;The page interface includes two additional methods, such as the &lt;br/&gt;
      &lt;b&gt;getTotalPages():&lt;/b&gt; gets the total number of pages accessible. &lt;br/&gt;
      &lt;b&gt;getTotalElements():&lt;/b&gt; The total number of elements is returned by getTotalElements().(alert-passed)&lt;/blockquote&gt;
      
    &lt;br/&gt;
    
    &lt;h3&gt;The page interface use case&lt;/h3&gt;
    &lt;p&gt;When you wish to display the number of pages available in the user interface (UI), utilize the Page interface. Because you may use the getTotalPages() function to display the number of pages.&lt;/p&gt;&lt;br/&gt;
    &lt;p&gt;for example, at the bottom of the e-commerce website, display the number of pages accessible to browse to the next or previous page or directly jump to the user's chosen page number.&lt;/p&gt; &lt;br/&gt;
    
    &lt;h3&gt;The Slice interface use case&lt;/h3&gt;
    &lt;p&gt;Use the Slice interface when you don't want to show the amount of records in the initial query or when you wish to fetch data on demand, such as on a lazy loading website, such as a social media site, where content is loaded while scrolling or hitting the load button.&lt;/p&gt; &lt;br/&gt;
      
  &lt;/div&gt; 
  
  &lt;br/&gt;
  
  &lt;div&gt;
    &lt;h2&gt;Conclussion&lt;/h2&gt;
    &lt;hr&gt;
    
    &lt;p&gt;We covered how to implement pagination in a Spring Boot application using Spring Data JPA in this instructional article.&lt;/p&gt;&lt;br/&gt;
    
    &lt;p&gt;We've seen the spring data JPA's default method, which includes pagination by default; however, we've also utilized pagination in a user-defined method or query.&lt;/p&gt;&lt;br/&gt;
    
    &lt;p&gt;In this post, you will not only learn about pagination, but also about sorting with the Sort class.&lt;/p&gt;&lt;br/&gt;
    
    &lt;p&gt;In the pagination concept, we learned about the various return type interfaces, such as the page interface and the slice interface, and we were able to differentiate between the two.&lt;/p&gt;&lt;br/&gt;
    
    &lt;p&gt;In addition, we go over the use cases for both the page interface and the slice interface in depth.&lt;/p&gt;&lt;br/&gt;
    &lt;p&gt;Keep learning and keep growing.&lt;/p&gt;
    
  &lt;/div&gt; 
  
 &lt;p align="right"&gt;&lt;a href="https://www.learnjavaskills.in/2023/08/spring-data-jpa-dto-projections.html"&gt;(getButton) #text=(Next: Spring Data JPA DTO Projections) #icon=(link) #color=(#2339bd)&lt;/a&gt;&lt;/p&gt;</content><link href="https://www.learnjavaskills.in/feeds/2917200440041767953/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/09/pagination-and-sorting-with-spring-data-jpa.html#comment-form" rel="replies" title="2 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/2917200440041767953" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/2917200440041767953" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/09/pagination-and-sorting-with-spring-data-jpa.html" rel="alternate" title="How to use Pagination and Sorting with Spring Data JPA | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcKt-7NAckDJ-SyjDelIIorZNLyNnnRH7CYFVDpAad_W8tgNwC6Vr5WO12-9X6E1mmSahfdZDZpjWsSR8IfO8GcZAi_sk1rA06Pzp6V6TBaFcrcNwNou9wNfV3TIQIiUUtZVUL0K_04WQ20XV1oNNLEpI_JMLp-On_ONDlw_Lc7jUzh2ncZRDKGjsam8O6/s72-c/Pagination%20new%20thumbnail.png" width="72"/><thr:total>2</thr:total><georss:featurename>United States</georss:featurename><georss:point>37.09024 -95.712891</georss:point><georss:box>8.780006163821156 -130.869141 65.400473836178847 -60.556641</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-7927265980043454711</id><published>2024-12-27T15:31:00.000+05:30</published><updated>2024-12-27T15:31:19.325+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">Spring Cloud AWS &amp; SQS: Streamline Your Development Workflow with Reliable Queuing | Learn Java Skills</title><content type="html">&lt;p&gt;Building modern, scalable applications sometimes need effective communication across many components. However, typical synchronous communication can cause bottlenecks and reduce performance.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Asynchronous messaging enables programs to exchange messages without waiting for a response, resulting in greater responsiveness and robustness.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;This blog article explains how to use &lt;b&gt;Spring Cloud AWS&lt;/b&gt; and &lt;b&gt;AWS SQS&lt;/b&gt; to establish strong asynchronous communication in your microservices architecture.&lt;/p&gt; &lt;br/&gt; 

&lt;p&gt;We'll walk you through integrating &lt;b&gt;SQS&lt;/b&gt; with your &lt;b&gt;Spring Boot&lt;/b&gt; application, sending and receiving messages, and dealing with any issues. By the conclusion, you'll have the knowledge and skills you need to improve communication inside your apps and grasp the benefits of an asynchronous approach.&lt;/p&gt; &lt;br/&gt;

&lt;strike&gt;toc&lt;/strike&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-and-amazon-sqs" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju4H75rFFnFAcARyylV195udKHuXWA3OxkLGsys03jU1_DiDWzyhoLCX8XJiqBQsIOoTk37xhVVzuSQ_LNTucARe0PMyZARCYll1VQvbcJqN2sg98oICMF8chbW2NT-ZFbn51taZ6OaAOe9Imn1JqDQzAE35hN8V9Dr0q3Sa56iM7amg92rnDydG5VB3Wo/s1600/thumbnail.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="spring cloud aws and amazon sqs thumbnail image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju4H75rFFnFAcARyylV195udKHuXWA3OxkLGsys03jU1_DiDWzyhoLCX8XJiqBQsIOoTk37xhVVzuSQ_LNTucARe0PMyZARCYll1VQvbcJqN2sg98oICMF8chbW2NT-ZFbn51taZ6OaAOe9Imn1JqDQzAE35hN8V9Dr0q3Sa56iM7amg92rnDydG5VB3Wo/s1600/thumbnail.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;h2&gt;Amazon Simple Queue Service (SQS)&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Amazon SQS offers queues for high-volume, system-to-system communications. Queues may be used to decouple heavyweight processes as well as buffer and batch operations.&lt;/p&gt; &lt;br/&gt;
  
&lt;p&gt;Amazon SQS retains messages until microservices and serverless applications can process them.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYjFWrUbnBXj40mQePsNrQam17BcNeFaz-2wLe4_zFfKcyRaJgJHE2wKeU6hITlu9VD2maTTn0b_fEpzOt2LVSFepMUB4SBuKIJ5_GbZd4fAlqRGgR7RVs_Sk52lqie-b8CMymFuqvTSpK8JB9F_h4j5SQQmLRrT1sn86BlMkGdFG0voqXtwSB2oJTV5BQ/s1600/Amazon%20SQS%20queue_2%20.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Amazon SQS diagram" border="0" data-original-height="870" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYjFWrUbnBXj40mQePsNrQam17BcNeFaz-2wLe4_zFfKcyRaJgJHE2wKeU6hITlu9VD2maTTn0b_fEpzOt2LVSFepMUB4SBuKIJ5_GbZd4fAlqRGgR7RVs_Sk52lqie-b8CMymFuqvTSpK8JB9F_h4j5SQQmLRrT1sn86BlMkGdFG0voqXtwSB2oJTV5BQ/s1600/Amazon%20SQS%20queue_2%20.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Amazon SQS enables producers to put messages into a queue. The messages are then saved in a SQS Queue. When consumers are ready to process new messages, they retrieve them from the queue.&lt;/p&gt; &lt;br/&gt;
  
&lt;p&gt;Applications, microservices, and numerous AWS services can function as either producers or consumers.&lt;/p&gt; &lt;br/&gt;

&lt;h2&gt;Spring Cloud AWS&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Spring Cloud for Amazon Web Services is an extension of the Spring Cloud umbrella project, which enables Spring Boot applications to easily communicate with Amazon Web Services.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Spring Cloud AWS provides an effortless way for accessing AWS services through well-known Spring idioms and APIs, such as the messaging or caching API.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Developers may design apps based on AWS hosted services without having to worry about infrastructure or maintenance.&lt;/p&gt; &lt;br/&gt;

&lt;h2&gt;Creating Your First Message Queue: A Step-by-Step Guide to Amazon SQS&lt;/h2&gt;
&lt;hr&gt;

&lt;h3&gt;Access the AWS Management Console:&lt;/h3&gt;

&lt;p&gt;Navigate to the AWS Management Console at &lt;a href="https://aws.amazon.com/console/" target="_blank" rel="nofollow"&gt;(getButton) #text=(Amazon Console) #icon=(link) #color=(#d35400)&lt;/a&gt; Sign in with your AWS credentials if you haven't already.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;Open the Amazon SQS service:&lt;/h3&gt;

&lt;p&gt;Search for &lt;code&gt;SQS&lt;/code&gt; in the search box or find it in the &lt;code&gt;Messaging&lt;/code&gt; category of the service list.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggHhfQc1PjirySZAE2fwHQZzT9DLUcf56HaDetLjgVG42SkEEzzACdtNGYqUtbq3wnnaQZO-8ai4SuWiKLp07W49pXiRTLqw-x2CnXXbJBM7v9-JlxBDDl0MddG1kDOb1nWUpFhphAhMrS3KI0H_UsHO92tNL1o-lc4zzTHQOmlTkhcrVI64x5Ow0KjxTz/s1600/type%20SQS.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Search SQS in the search box" border="0" data-original-height="244" data-original-width="908" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggHhfQc1PjirySZAE2fwHQZzT9DLUcf56HaDetLjgVG42SkEEzzACdtNGYqUtbq3wnnaQZO-8ai4SuWiKLp07W49pXiRTLqw-x2CnXXbJBM7v9-JlxBDDl0MddG1kDOb1nWUpFhphAhMrS3KI0H_UsHO92tNL1o-lc4zzTHQOmlTkhcrVI64x5Ow0KjxTz/s1600/type%20SQS.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;h3&gt;Create a new queue:&lt;/h3&gt;

&lt;p&gt;Click on the &lt;code&gt;Create queue&lt;/code&gt; button.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMjn-m_y5CO_enDXGIXHkZ8-PJEKNcXuQ55QZrQUGL9_VxzltGAyHicm5Frl14q9XYWjVR4PkB9R2eD99Ek_oD_xnuPUwuVGJu7JCXzkTh7itKDlAzhfVyC9OL55VCdE6mirwd_ARZtyT9NeIVxCnKNPRkR4VV986Xw5CicXnOAMsF7k9MJZFgQmiSIeZM/s1600/create%20queue%20-%20step%202.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Create Queue" border="0" data-original-height="569" data-original-width="1236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMjn-m_y5CO_enDXGIXHkZ8-PJEKNcXuQ55QZrQUGL9_VxzltGAyHicm5Frl14q9XYWjVR4PkB9R2eD99Ek_oD_xnuPUwuVGJu7JCXzkTh7itKDlAzhfVyC9OL55VCdE6mirwd_ARZtyT9NeIVxCnKNPRkR4VV986Xw5CicXnOAMsF7k9MJZFgQmiSIeZM/s1600/create%20queue%20-%20step%202.png"/&gt;&lt;/a&gt;&lt;/div&gt; &lt;br/&gt;

&lt;p&gt;Choose an appropriate name for your queue. In my situation, I named the &lt;code&gt;my-first queue&lt;/code&gt;. Amazon SQS offers two types of queues: &lt;code&gt;Standard&lt;/code&gt; and &lt;code&gt;FIFO&lt;/code&gt;. For this example, I'll be creating a &lt;b&gt;standard&lt;/b&gt; queue.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZpDp7Mcdbq7iZwWwkiygaoQJ0MiX39aFS7ZAyU2YPopvgn07oI4s09Cp7DIXYHt1ZBowddES2Zjdl7BeN9-d2_9Dy3tLxotb7Hm_U7jTPnrb5k4Do14Hms7sRX-vwhLlI9VVE4rfEGFJZzgcMdqDCKl9pA1p339Dia9TeVK4Aj8D-OpT2Egjm3eP-wU7F/s1600/my-first-queue-step-3.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="my-first-queue" border="0" data-original-height="546" data-original-width="1024" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZpDp7Mcdbq7iZwWwkiygaoQJ0MiX39aFS7ZAyU2YPopvgn07oI4s09Cp7DIXYHt1ZBowddES2Zjdl7BeN9-d2_9Dy3tLxotb7Hm_U7jTPnrb5k4Do14Hms7sRX-vwhLlI9VVE4rfEGFJZzgcMdqDCKl9pA1p339Dia9TeVK4Aj8D-OpT2Egjm3eP-wU7F/s1600/my-first-queue-step-3.png"/&gt;&lt;/a&gt;&lt;/div&gt; &lt;br/&gt;

&lt;p&gt;You can leave the default settings for most use cases or customize them based on your specific needs (e.g., visibility timeout, message retention period).&lt;/p&gt; 

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6pe_oOnqcPbOBIQqwC5T5Hruj-Cc1g5lQrF_1BDrAYHdDb-VGltvFaWTWa1f25n79kvZXzoFZI3p-h4mFZgV-uwe4QaCSIwr0dUcZg7mhDmS_hyphenhyphenacSx7BbtcBdQ9O3w-rR4-DVMSRMFOSIBBuAJ-Hbx4Q7puJnxFgUg3tKANv63a3fC0vs928UjRl5YdS/s1600/configuration%20step%204.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="default-setting-visibility-timeout-in-sqs" border="0" data-original-height="414" data-original-width="1018" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6pe_oOnqcPbOBIQqwC5T5Hruj-Cc1g5lQrF_1BDrAYHdDb-VGltvFaWTWa1f25n79kvZXzoFZI3p-h4mFZgV-uwe4QaCSIwr0dUcZg7mhDmS_hyphenhyphenacSx7BbtcBdQ9O3w-rR4-DVMSRMFOSIBBuAJ-Hbx4Q7puJnxFgUg3tKANv63a3fC0vs928UjRl5YdS/s1600/configuration%20step%204.png"/&gt;&lt;/a&gt;&lt;/div&gt; &lt;br/&gt;

&lt;p&gt;Configure the access policy to determine who may send and receive messages from this queue. I created an IAM user, &lt;code&gt;sqs-queue-read-write&lt;/code&gt;, to send and receive messages programmatically. Must provide the ARN of the IAM user here.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRIK3SCNybvfSLRAFUFXQVXg97gukz6NvSTccTnt6Iysa9cqTMUu9IlFjD-J-0luzE5U8v__LC6jRUyS12PM1HJhFfw7696hPYLGaCz2WjrXbFg5nlFhSCa6Fr6Ufi97GAuTJN4o82ovPeB1NW-yd0fs1WhFGNySSLuLLtgTNQ9bMo5x6eZlg6IwTXxDW6/s1600/access%20policy%20step%20-hide%20-%2026.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="SQS-queue-access-policy" border="0" data-original-height="592" data-original-width="918" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRIK3SCNybvfSLRAFUFXQVXg97gukz6NvSTccTnt6Iysa9cqTMUu9IlFjD-J-0luzE5U8v__LC6jRUyS12PM1HJhFfw7696hPYLGaCz2WjrXbFg5nlFhSCa6Fr6Ufi97GAuTJN4o82ovPeB1NW-yd0fs1WhFGNySSLuLLtgTNQ9bMo5x6eZlg6IwTXxDW6/s1600/access%20policy%20step%20-hide%20-%2026.png"/&gt;&lt;/a&gt;&lt;/div&gt;


&lt;p&gt;Click on &lt;code&gt;Create queue&lt;/code&gt; to finalize the process.&lt;/p&gt;
&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaUWawsHG4BPnXrVMBZIFgn5vH1051p8sMBrUvsnrvZJ7sovcKmh_mJaHMrf7-KtgW4_-govM5n6Q3OuBnTVk7Slj1sNbC-xoUwXi1zgxERHu9Ag2DZF9dpbmjHP69g7SM8xRTXpEYQ7aUkNM_PcAGqAcacFFR6w7_lLp4gQL4p-xT0SGfZwmBIfY0ZaHv/s1600/create%20queue%20final%20step.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="create-queue-final" border="0" data-original-height="481" data-original-width="958" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaUWawsHG4BPnXrVMBZIFgn5vH1051p8sMBrUvsnrvZJ7sovcKmh_mJaHMrf7-KtgW4_-govM5n6Q3OuBnTVk7Slj1sNbC-xoUwXi1zgxERHu9Ag2DZF9dpbmjHP69g7SM8xRTXpEYQ7aUkNM_PcAGqAcacFFR6w7_lLp4gQL4p-xT0SGfZwmBIfY0ZaHv/s1600/create%20queue%20final%20step.png"/&gt;&lt;/a&gt;&lt;/div&gt; &lt;br/&gt;


&lt;h2&gt;Spring Cloud AWS and SQS: Essential Dependencies for Streamlining Your Messaging&lt;/h2&gt;
&lt;hr&gt;


&lt;p&gt;spring-cloud-aws-starter-sqs: Provides messaging abstractions for sending and receiving messages.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code&gt; // spring cloud aws BOM(Bill of materials)
 implementation platform(&amp;quot;io.awspring.cloud:spring-cloud-aws-dependencies:${springCloudAwsVersion}&amp;quot;)
 // Amazon SQS 
 implementation &amp;#39;io.awspring.cloud:spring-cloud-aws-starter-sqs&amp;#39;&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Configuring Amazon SQS in Spring Cloud AWS&lt;/h2&gt;
&lt;hr&gt;

&lt;h3&gt;Securely Configuring AWS Credentials: Different Approaches&lt;/h3&gt;

&lt;p&gt;Spring Cloud AWS starter automatically configures a &lt;code&gt;DefaultCredentialsProvider&lt;/code&gt; that checks for AWS credentials in the following order:&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;b&gt;Java System Properties&lt;/b&gt;: &lt;code&gt;aws.accessKeyId&lt;/code&gt;, &lt;code&gt;aws.secretAccessKey&lt;/code&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&amp;#x2022; Environment variables include &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; and &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&amp;#x2022; Credentials for Web Identity Token can be obtained from system configurations or environmental variables.&lt;/p&gt; &lt;br/&gt;

  &lt;p&gt;&amp;#x2022; Credential profiles are stored in the default directory &lt;code&gt;(~/.aws/credentials)&lt;/code&gt; used by all AWS SDKs and the AWS CLI.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&amp;#x2022; Credentials provided through the Amazon EC2 container service if the &lt;code&gt;AWS_CONTAINER_CREDENTIALS_RELATIVE_URI&lt;/code&gt; environment variable is defined and the security manager has access to the variable.&lt;/p&gt; &lt;br/&gt;

  &lt;p&gt;&amp;#x2022; Instance profile credentials are given via the Amazon EC2 metadata service.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;Configuring SQS Properties in Application.properties&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt; # Amazon SQS configuration
spring.cloud.aws.credentials.access-key=${AWS_ACCESS_KEY_ID}
spring.cloud.aws.credentials.secret-key=${AWS_SECRET_ACCESS_KEY}
spring.cloud.aws.region.static=${AWS_REGION}
spring.cloud.aws.sqs.endpoint=${SQS_ENDPOINT}&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Granting IAM User Access to an SQS Queue&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Securely grant your IAM user the required permissions to interact with the SQS queue within your account.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "json"&gt; {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "sqs-read-and-write-policy",
            "Effect": "Allow",
            "Action": [
                "sqs:DeleteMessage",
                "sqs:GetQueueUrl",
                "sqs:ReceiveMessage",
                "sqs:SendMessage",
                "sqs:GetQueueAttributes"
            ],
            "Resource": "your sqs arn e.g: arn:aws:sqs:*:123456789012:*"
        }
    ]
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;h2&gt;Sending a Message to an Amazon SQS Queue&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Spring Cloud AWS offers the &lt;code&gt;SqsTemplate&lt;/code&gt; for sending messages to the Amazon SQS.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Using SqsTemplate for SQS Messaging&lt;/h3&gt;

&lt;p&gt;When leveraging Spring Boot and autoconfiguration, a &lt;code&gt;SqsTemplate&lt;/code&gt; instance is automatically autowired if no other template bean is detected in the context.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;This template instance is supported by the autoconfigured &lt;code&gt;SqsAsyncClient&lt;/code&gt;, which accepts any configurations given. SqsTemplates are immutable and thread-safe.&lt;/p&gt; &lt;br/&gt;


&lt;p&gt;If more extensive setup is preferred, a builder is also provided along with a set of options.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.sqsmessaging.configuration;

 import io.awspring.cloud.sqs.operations.SqsTemplate;
 import io.awspring.cloud.sqs.operations.TemplateAcknowledgementMode;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import software.amazon.awssdk.services.sqs.SqsAsyncClient;

 import java.time.Duration;

 @Configuration
 public class SqsTemplateConfiguration
 {
    @Bean
    public SqsTemplate sqsTemplate(SqsAsyncClient sqsAsyncClient)
    {
        return SqsTemplate.builder()
                .sqsAsyncClient(sqsAsyncClient)
                .configure(options -&gt; options
                        .acknowledgementMode(TemplateAcknowledgementMode.MANUAL)
                        .defaultQueue("my-first-queue")
                        .defaultPollTimeout(Duration.ofSeconds(5))
                        .defaultMaxNumberOfMessages(5)
                )
                .build();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;


&lt;h3&gt;Sending Messages with SqsTemplate&lt;/h3&gt;

&lt;p&gt;There are several methods for sending messages to SQS queues using the &lt;code&gt;SqsTemplate&lt;/code&gt;. The &lt;code&gt;SqsOperations&lt;/code&gt; interface provides the following methods, which have async equivalents in &lt;code&gt;SqsAsyncOperations&lt;/code&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;Method&lt;/th&gt;
    &lt;th&gt;Description&lt;/th&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;SendResult&amp;lt;T&amp;gt; send(String queue, T payload);&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;Send a message to the provided queue with the given payload&lt;/td&gt;
  &lt;tr&gt; 
    
   &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;SendResult&amp;lt;T&amp;gt; send(T payload);&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;Send a message to the configured default endpoint&lt;/td&gt;
  &lt;tr&gt;
    
   &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;SendResult&amp;lt;T&amp;gt; send(String queue, Message&amp;lt;T&amp;gt; message);&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;Send the given Message to the provided queue&lt;/td&gt;
  &lt;tr&gt;   
  
    
    &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;SendResult&amp;lt;T&amp;gt; send(Consumer&amp;lt;SqsSendOptions&amp;gt; to);&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;Send a message with the provided options&lt;/td&gt;
  &lt;tr&gt; 
    
    &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;SendResult.Batch&amp;lt;T&amp;gt; sendMany(String queue, Collection&amp;lt;Message&amp;lt;T&amp;gt;&amp;gt; messages);&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;Send a batch of Messages to the provided queue&lt;/td&gt;
  &lt;tr&gt;  
&lt;/table&gt;  &lt;br/&gt;


&lt;p&gt;An example using the &lt;code&gt;SqsSendOptions&lt;/code&gt; variant follows: &lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; SendResult&amp;lt;Object&amp;gt; sendResult = sqsTemplate.send(to -&amp;gt; to.queue(&amp;quot;my-first-queue&amp;quot;)
	.payload(&amp;quot;Hello,  My first message to amazon SQS&amp;quot;)
	.header(&amp;quot;header1&amp;quot;, &amp;quot;header-value1&amp;quot;)
	.delaySeconds(2));&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;An example of sending a message using a Java class is: &lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; Employee employee = new Employee(&amp;quot;name&amp;quot;, &amp;quot;designation&amp;quot;, &amp;quot;department&amp;quot;);
 SendResult&amp;lt;Object&amp;gt; sendResult = sqsTemplate.send(to -&amp;gt;to.queue(&amp;quot;my-first-queue&amp;quot;)
	.payload(employee)
	.header(&amp;quot;header1&amp;quot;, &amp;quot;header-value1&amp;quot;)
	.headers(Map.of(&amp;quot;My-second-header&amp;quot;, &amp;quot;my-second-header-value&amp;quot;))
	.delaySeconds(1));&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;Understanding the SendResult of SqsTemplate.send&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;SendResult&lt;/code&gt; &lt;a href="https://www.learnjavaskills.in/2023/09/what-is-a-record-in-java.html"&gt;record&lt;/a&gt; offers helpful information about the sending operation.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public record SendResult&amp;lt;T&amp;gt;(UUID messageId, String endpoint, Message&amp;lt;T&amp;gt; message, Map&amp;lt;String, Object&amp;gt; additionalInformation) {
    public record Batch&amp;lt;T&amp;gt;(Collection&amp;lt;SendResult&amp;lt;T&amp;gt;&amp;gt; successful, Collection&amp;lt;SendResult.Failed&amp;lt;T&amp;gt;&amp;gt; failed) {}
    public record Failed&amp;lt;T&amp;gt; (String errorMessage, String endpoint, Message&amp;lt;T&amp;gt; message, Map&amp;lt;String, Object&amp;gt; additionalInformation) {}
 } &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;p&gt;When the send actions succeeds, the &lt;b&gt;SendResult&lt;/b&gt; object is created with:&lt;/p&gt; &lt;br/&gt;

&lt;table&gt;
 
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;messageId&lt;/code&gt;&lt;/td&gt;
   	 &lt;td&gt;The &lt;b&gt;messageId&lt;/b&gt; returned from SQS for the message&lt;/td&gt;  
  &lt;tr&gt;
    
  &lt;tr&gt;
     &lt;td&gt;&lt;code&gt;endpoint&lt;/code&gt;&lt;/td&gt;
   	 &lt;td&gt;The &lt;b&gt;endpoint&lt;/b&gt; the message was sent to&lt;/td&gt;  
  &lt;tr&gt;  
    
  &lt;tr&gt;
     &lt;td&gt;&lt;code&gt;Message&lt;/code&gt;&lt;/td&gt;
   	 &lt;td&gt;The &lt;b&gt;Message&lt;/b&gt; instance that was sent, with any additional headers that might have been added by the framework&lt;/td&gt;  
  &lt;tr&gt;  
    
  &lt;tr&gt;
     &lt;td&gt;&lt;code&gt;additionalInformation&lt;/code&gt;&lt;/td&gt;
   	 &lt;td&gt;An &lt;b&gt;additionalInformation&lt;/b&gt; map with the &lt;b&gt;sequenceNumber&lt;/b&gt; generated for the message in &lt;b&gt;Fifo&lt;/b&gt; queues&lt;/td&gt;  
  &lt;tr&gt;    
&lt;/table&gt;  &lt;br/&gt;

&lt;p&gt;When the send operation for a single message fails, a &lt;code&gt;MessagingOperationFailedException&lt;/code&gt; is thrown, which contains the message.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;For &lt;code&gt;Batch&lt;/code&gt; send operations, a &lt;code&gt;SendResult.Batch&lt;/code&gt; object is returned. This object includes a collection of successful and failed results.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;If any messages failed to be sent inside a batch, return the relevant &lt;code&gt;SendResult.Failed&lt;/code&gt; objects are created.&lt;/p&gt; &lt;br/&gt;

&lt;h2&gt;Receiving Messages with SqsTemplate&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;The &lt;code&gt;SqsTemplate&lt;/code&gt; provides handy methods for receiving messages from the &lt;b&gt;Standard&lt;/b&gt; and &lt;b&gt;FIFO&lt;/b&gt; SQS queues.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;These methods are divided into two interfaces that &lt;u&gt;SqsTemplate&lt;/u&gt; implements: &lt;code&gt;SqsOperations&lt;/code&gt; and &lt;code&gt;SqsAsyncOperations&lt;/code&gt;. If just sync or async actions are required, utilizing the specified interface might help cut down the options.&lt;/p&gt; &lt;br/&gt;
  
&lt;p&gt;The &lt;b&gt;SqsOperations&lt;/b&gt; interface provides the following methods, which have async equivalents in &lt;code&gt;SqsAsyncOperations&lt;/code&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;Method&lt;/th&gt;
    &lt;th&gt;Description&lt;/th&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;Optional&amp;lt;Message&amp;lt;?&amp;gt;&amp;gt; receive();&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;Receive a message from the configured default endpoint and options&lt;/td&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;&amp;lt;T&amp;gt; Optional&amp;lt;Message&amp;lt;T&amp;gt;&amp;gt; receive(String queue, Class&amp;lt;T&amp;gt; payloadClass);&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;Receive a message from the provided queue and convert the payload to the provided class&lt;/td&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;Optional&amp;lt;Message&amp;lt;?&amp;gt;&amp;gt; receive(Consumer&amp;lt;SqsReceiveOptions&amp;gt; from);&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;Receive a message with the provided options&lt;/td&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;&amp;lt;T&amp;gt; Optional&amp;lt;Message&amp;lt;T&amp;gt;&amp;gt; receive(Consumer&amp;lt;SqsReceiveOptions&amp;gt; from, Class&amp;lt;T&amp;gt; payloadClass);&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
    &lt;td&gt;Receive a message with the provided options and convert the payload to the provided class&lt;/td&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;Collection&amp;lt;Message&amp;lt;?&amp;gt;&amp;gt; receiveMany();&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;Receive a batch of messages from the configured default endpoint and options.&lt;/td&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;&amp;lt;T&amp;gt; Collection&amp;lt;Message&amp;lt;T&amp;gt;&amp;gt; receiveMany(String queue, Class&amp;lt;T&amp;gt; payloadClass);&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;Receive a batch of messages from the provided queue and convert the payloads to the provided class.&lt;/td&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;Collection&amp;lt;Message&amp;lt;?&amp;gt;&amp;gt; receiveMany(Consumer&amp;lt;SqsReceiveOptions&amp;gt; from);&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;Receive a batch of messages with the provided options&lt;/td&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;pre&gt;&lt;code class = "java"&gt;&amp;lt;T&amp;gt; Collection&amp;lt;Message&amp;lt;T&amp;gt;&amp;gt; receiveMany(Consumer&amp;lt;SqsReceiveOptions&amp;gt; from, Class&amp;lt;T&amp;gt; payloadClass);&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;Receive a batch of messages with the provided options and convert the payloads to the provided class.&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;  &lt;br/&gt;

&lt;p&gt;The following is an example for receiving a message with options:&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; Optional&amp;lt;Message&amp;lt;Employee&amp;gt;&amp;gt; receivedMessage = sqsTemplate.receive(from -&amp;gt; from.queue(&amp;quot;my-first-queue&amp;quot;)
	.visibilityTimeout(Duration.ofSeconds(10))
	.pollTimeout(Duration.ofSeconds(10)), Employee.class); &lt;/code&gt;&lt;/pre&gt;


&lt;blockquote&gt;The SqsTemplate by default acknowledges all received messages, which can be changed by setting TemplateAcknowledgementMode.MANUAL in the template options:(alert-warning)&lt;/blockquote&gt;

&lt;pre&gt;&lt;code class = "java"&gt; SqsTemplate.builder()
	.configure(options -&gt; 
    	options.acknowledgementMode(TemplateAcknowledgementMode.MANUAL));&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;


&lt;h2&gt;Consuming Messages from SQS Queues using @SqsListener&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;The easiest approach to consume SQS messages is to use the &lt;code&gt;@SqsListener&lt;/code&gt; annotation on a method in a &lt;code&gt;@Component&lt;/code&gt; class.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The framework will then build the &lt;code&gt;MessageListenerContainer&lt;/code&gt; and configure a &lt;code&gt;MessagingMessageListenerAdapter&lt;/code&gt; to call the method whenever a message is received.&lt;/p&gt; &lt;br/&gt;


&lt;h3&gt;Defining Queue Names for @SqsListener Annotation (Spring Cloud AWS)&lt;/h3&gt;
&lt;p&gt;One or more queues can be provided in the annotation using either the &lt;code&gt;queueNames&lt;/code&gt; or &lt;code&gt;value&lt;/code&gt; attributes; there is no differentiation between the two.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Queue URLs can be used instead of queue names. Using urls instead of queue names might result in significantly faster startup times since it prevents the framework from searching for the queue url when the containers start.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @SqsListener({&amp;quot;my-first-queue&amp;quot;, &amp;quot;${my.second.queue.url}&amp;quot;})
 public void listener(String message) {
    System.out.println(&amp;quot;received message : &amp;quot;  + message);
 }&lt;/code&gt;&lt;/pre&gt; 

&lt;blockquote&gt;Any number of @SqsListener annotations can be used in a bean class, and each annotated method will be handled by a separate MessageListenerContainer.(alert-success)&lt;/blockquote&gt;


&lt;h3&gt;Configuring Advanced Options with @SqsListener&lt;/h3&gt;

&lt;p&gt;The following properties can be supplied using the &lt;code&gt;@SqsListener&lt;/code&gt; annotation. Such properties override the corresponding &lt;code&gt;SqsContainerOptions&lt;/code&gt; for the generated &lt;code&gt;MessageListenerContainer&lt;/code&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;id&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Indicate the resultant container's id. This may be used to retrieve the container from the &lt;b&gt;MessageListenerContainerRegistry&lt;/b&gt;, and it is also utilized by the container and its components for general logging and thread identification.&lt;/td&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;maxConcurrentMessages&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Determine the maximum number of messages that can be in flight at any given point in time.&lt;/td&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;pollTimeoutSeconds&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Set the maximum amount of time to wait for a poll to return from SQS. Please keep in mind that if there are messages available, the call may return before this time.&lt;/td&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;messageVisibilitySeconds&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Set the minimum visibility for messages collected in a poll. Note that for FIFO single message listener methods, this visibility is applied to the whole batch before each message is delivered to the listener.&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;  &lt;br/&gt;

&lt;p&gt;Here's an example of @SqsListener annotation properties:&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @SqsListener(queueNames = &amp;quot;my-first-queue&amp;quot;, id = &amp;quot;my-first-queue-id&amp;quot;,
            maxConcurrentMessages = &amp;quot;10&amp;quot;, pollTimeoutSeconds = &amp;quot;2&amp;quot;,
            messageVisibilitySeconds = &amp;quot;2&amp;quot;)
 public void listener(Message&amp;lt;Employee&amp;gt; message) {
   System.out.println(&amp;quot;received message : &amp;quot;  + message.getPayload());
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;Understanding Listener Method Arguments in @SqsListener&lt;/h3&gt;

&lt;p&gt;The listener method signature allows a variety of argument types, which are as follows:&lt;/p&gt; &lt;br/&gt;

&lt;table&gt;
  
  &lt;tr&gt;
    &lt;th&gt;Listener Method Arguments&lt;/th&gt;
    &lt;th&gt;Description&lt;/th&gt;  
  &lt;/tr&gt;  
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;MyPojo&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;POJO types are automatically de-serialized from JSON.&lt;/td&gt;
  &lt;tr/&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;Message&amp;lt;MyPojo&amp;gt;&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Retrieves a &lt;b&gt;Message&amp;lt;MyPojo&amp;gt;&lt;/b&gt; object with deserialized payload and MessageHeaders.&lt;/td&gt;
  &lt;tr/&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;List&amp;lt;MyPojo&amp;gt;&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Enables batch mode and gets the batch polled by SQS.&lt;/td&gt;
  &lt;tr/&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;List&amp;lt;Message&amp;lt;MyPojo&amp;gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Enables batch mode and gets the batch polled from SQS, featuring all the headers.&lt;/td&gt;
  &lt;tr/&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;@Header(String headerName)&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;provides the specified header.&lt;/td&gt;
  &lt;tr/&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;@Headers&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;provides the MessageHeaders or a Map&amp;lt;String, Object&amp;gt;&lt;/td&gt;
  &lt;tr/&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;Acknowledgement&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;provides methods for manually acknowledging messages for individual message listeners. AcknowledgementMode must be set to Manual.&lt;/td&gt;
  &lt;tr/&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;BatchAcknowledgement&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Batch listeners can manually acknowledge partial or entire message batches. AcknowledgementMode must be set to Manual.&lt;/td&gt;
  &lt;tr/&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;Visibility&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;provides the changeTo() method that enables changing the message’s visibility to the provided value.&lt;/td&gt;
  &lt;tr/&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;QueueAttributes&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;Provides queue attributes for the message's receiving queue. &lt;/td&gt;
  &lt;tr/&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;&lt;code&gt;software.amazon.awssdk.services.sqs.model.Message&lt;/code&gt;&lt;/td&gt;
    &lt;td&gt;provides the original Message from SQS&lt;/td&gt;
  &lt;tr/&gt; 
&lt;/table&gt;  &lt;br/&gt;

&lt;p&gt;Here's an example with multiple arguments:&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @SqsListener(&amp;quot;my-first-queue&amp;quot;)
 public void listener(Message&amp;lt;Employee&amp;gt; message, MessageHeaders messageHeaders,
		 Visibility visibility, QueueAttributes queueAttributes, Acknowledgement acknowledgement,
		 software.amazon.awssdk.services.sqs.model.Message originalMessage) {
         
	System.out.println(&amp;quot;received message : &amp;quot;  + message.getPayload());
	System.out.println(&amp;quot;message header : &amp;quot; + messageHeaders.toString());

	acknowledgement.acknowledge();
	visibility.changeTo(10);

	String queueUrl = queueAttributes.getQueueUrl();
	System.out.println(&amp;quot;queue url : &amp;quot; + queueUrl);

	System.out.println(&amp;quot;original message : &amp;quot; + originalMessage.toString());
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;blockquote&gt;Batch listeners support a single List&amp;lt;MyPojo&amp;gt; and List&amp;lt;Message&amp;lt;MyPojo&amp;gt;&amp;gt; method arguments, and an optional BatchAcknowledgement or AsyncBatchAcknowledgement arguments. MessageHeaders should be extracted from the Message instances through the getHeaders() method.(alert-warning)&lt;/blockquote&gt;


&lt;h2&gt;Handling Failed Messages: Configuring a Dead-Letter Queue for Amazon SQS&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Let's delve deeper into robust message handling. This &lt;a href="https://www.learnjavaskills.in/2024/12/configure-dead-letter-queue-for-amazon-sqs.html"&gt;(getButton) #text=(Dead-Letter Queue for Amazon SQS) #icon=(link) #color=(#35a576)&lt;/a&gt; post will guide you through configuring a Dead-Letter Queue (DLQ) for your SQS queues, ensuring that failed messages are properly captured and managed for troubleshooting and recovery.&lt;/p&gt;&lt;br/&gt;

&lt;h2&gt;Conclusion: Leveraging SQS with Spring Cloud AWS&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;In this blog post, we looked at how Amazon SQS and Spring Cloud AWS can work together to provide robust message queuing in your application. We looked into:&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;b&gt;Creating a SQS Queue in the AWS Console&lt;/b&gt;: To establish the foundation, we demonstrated how to create your SQS queue.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;b&gt;Sending and Receiving Messages with SqsTemplate&lt;/b&gt;: We showed how to effectively send and retrieve messages using the Spring Cloud AWS SqsTemplate class.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;b&gt;Using the @SqlListener annotation&lt;/b&gt;: We looked into the @SqsListener annotation, which provides a strong method for asynchronous message ingestion from a SQS queue.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;By combining these principles, you provide your Spring Cloud AWS application with the capability to:&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;b&gt;Decouple services&lt;/b&gt;: Create loose coupling between services by outsourcing communication to an asynchronous message queue.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;b&gt;Increase scalability and fault tolerance&lt;/b&gt;: SQS makes it easier to handle traffic surges and allows individual services to continue processing messages even if they fail.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;b&gt;Improve message delivery reliability&lt;/b&gt;: SQS assures at-least-once delivery, guaranteeing that your messages reach their target.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;By incorporating SQS into your Spring Cloud AWS environment, you acquire a powerful tool for creating strong, scalable, and resilient messaging-driven systems. We urge you to experiment and discover how SQS might help your apps communicate and manage messages more efficiently.&lt;/p&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-and-amazon-sqs" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt; 

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;












  






</content><link href="https://www.learnjavaskills.in/feeds/7927265980043454711/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/03/spring-cloud-aws-and-amazon-sqs.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/7927265980043454711" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/7927265980043454711" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/03/spring-cloud-aws-and-amazon-sqs.html" rel="alternate" title="Spring Cloud AWS &amp; SQS: Streamline Your Development Workflow with Reliable Queuing | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju4H75rFFnFAcARyylV195udKHuXWA3OxkLGsys03jU1_DiDWzyhoLCX8XJiqBQsIOoTk37xhVVzuSQ_LNTucARe0PMyZARCYll1VQvbcJqN2sg98oICMF8chbW2NT-ZFbn51taZ6OaAOe9Imn1JqDQzAE35hN8V9Dr0q3Sa56iM7amg92rnDydG5VB3Wo/s72-c/thumbnail.png" width="72"/><thr:total>0</thr:total><georss:featurename>India</georss:featurename><georss:point>20.593684 78.96288</georss:point><georss:box>-53.58864270872121 -61.66212 90 -140.41212000000002</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-906003920259939347</id><published>2024-12-27T15:13:00.011+05:30</published><updated>2024-12-27T15:19:33.185+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><title type="text">How to configure a Dead-Letter Queue (DLQ) for Amazon SQS</title><content type="html">&lt;section&gt;
  &lt;div&gt;
    &lt;p&gt;
      Dead letter queues (DLQs) are crucial in distributed systems for handling
      failed message processing. They isolate problematic messages, preventing
      main queue blockage and enabling investigation, retry attempts, or
      archiving for later analysis, ensuring no data loss.
    &lt;/p&gt;
    &lt;br /&gt;

    &lt;p&gt;
      This lesson covers enabling and creating dead-letter queues in Amazon SQS.
    &lt;/p&gt;

    &lt;blockquote&gt;
      The dead-letter queue of a FIFO queue must also be a FIFO queue.
      Similarly, the dead-letter queue of a standard queue must also be a
      standard queue.(alert-warning)
    &lt;/blockquote&gt;
  &lt;/div&gt;
&lt;/section&gt;

&lt;div class="separator" style="clear: both;"&gt;
  &lt;a
    href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQPJ2ikXQnfeqISMEF05SeWH8dVmiqDuhjbFLOkm8_mE8CWFh-Oa-WiPO676WVVhcPQZogFGik-jEnAV51EVp1dAJckzZbfw0ODyMTQX_BcFA1uRRFcNDi7KXHlEX1BlvdpPO-0nkEqfNfd5Un1qnqzooMOMR3LeKR42ItRKzH7YRF_euAH-YzKtEtNpAs/s1600/Dead%20Letter%20Queue%20Thumbnail.png"
    style="display: block; padding: 1em 0; text-align: center; "
    &gt;&lt;img
      alt="Thumbnail Image"
      border="0"
      data-original-height="1080"
      data-original-width="1920"
      src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQPJ2ikXQnfeqISMEF05SeWH8dVmiqDuhjbFLOkm8_mE8CWFh-Oa-WiPO676WVVhcPQZogFGik-jEnAV51EVp1dAJckzZbfw0ODyMTQX_BcFA1uRRFcNDi7KXHlEX1BlvdpPO-0nkEqfNfd5Un1qnqzooMOMR3LeKR42ItRKzH7YRF_euAH-YzKtEtNpAs/s1600/Dead%20Letter%20Queue%20Thumbnail.png"
  /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;strike&gt;toc&lt;/strike&gt;
&lt;br /&gt;

&lt;!-- creating dead-letter queue using AWS CLI --&gt;
&lt;section&gt;
  &lt;div&gt;
    &lt;h2&gt;Creating and Configuring Dead-Letter Queues using the AWS CLI&lt;/h2&gt;
    &lt;hr /&gt;

    &lt;p&gt;
      The AWS CLI provides a simple method for configuring dead-letter queues
      (DLQs) in Amazon SQS. The process requires first creating an SQS queue to
      serve as the DLQ, followed by creating the primary queue and configuring
      it to send failed messages to the designated DLQ.
    &lt;/p&gt;
    &lt;br /&gt;

    &lt;section&gt;
      &lt;h3&gt;Creating a Dead-Letter Queue&lt;/h3&gt;
      &lt;pre&gt;&lt;code class = "bash"&gt; aws sqs create-queue --queue-name dead-letter-queue&lt;/code&gt;&lt;/pre&gt;
      &lt;br /&gt;

      &lt;p&gt;
        After successfully executing the script, you will receive a JSON
        response containing the URL of the created SQS queue.
      &lt;/p&gt;
      &lt;br /&gt;
      &lt;pre&gt;&lt;code class = "json"&gt; {
    &amp;#x22;QueueUrl&amp;#x22;: &amp;#x22;https://sqs.us-east-1.amazonaws.com/123456789012/dead-letter-queue&amp;#x22;
 }&lt;/code&gt;&lt;/pre&gt;
      &lt;br /&gt;
    &lt;/section&gt;

    &lt;section&gt;
      &lt;h3&gt;
        Creating a Standard SQS Queue with Dead-Letter Queue Configuration and
        Redrive Policy
      &lt;/h3&gt;

      &lt;p&gt;
        Create a JSON file containing the following
        &lt;code&gt;RedrivePolicy&lt;/code&gt; details, which are required to configure a
        dead-letter queue when creating a new Amazon SQS queue.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;pre&gt;&lt;code class = "json"&gt; {
  &amp;#x22;RedrivePolicy&amp;#x22;: &amp;#x22;{\&amp;#x22;deadLetterTargetArn\&amp;#x22;:\&amp;#x22;arn:aws:sqs:us-east-1:123456789012:dead-letter-queue\&amp;#x22;,\&amp;#x22;maxReceiveCount\&amp;#x22;:\&amp;#x22;3\&amp;#x22;}&amp;#x22;,
  &amp;#x22;MessageRetentionPeriod&amp;#x22;: &amp;#x22;259200&amp;#x22;
 } &lt;/code&gt;&lt;/pre&gt;
      &lt;br /&gt;

      &lt;p&gt;
        To create the new Amazon SQS queue, use the same AWS CLI create-queue
        command as before, but this time include the
        &lt;code&gt;--attributes&lt;/code&gt; flag and specify the path to the JSON file.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;pre&gt;&lt;code class = "bash"&gt; aws sqs create-queue --queue-name main-queue --attributes file://create-queue.json&lt;/code&gt;&lt;/pre&gt;
      &lt;br /&gt;

      &lt;pre&gt;&lt;code class = "json"&gt; {
    &amp;#x22;QueueUrl&amp;#x22;: &amp;#x22;https://sqs.us-east-1.amazonaws.com/123456789012/main-queue&amp;#x22;
 }&lt;/code&gt;&lt;/pre&gt;
      &lt;br /&gt;
    &lt;/section&gt;

    &lt;h3&gt;What is a RedrivePolicy in the context of dead-letter queues?&lt;/h3&gt;
    &lt;p&gt;
      A &lt;code&gt;RedrivePolicy&lt;/code&gt; specifies how messages are moved from the
      main queue to the DLQ after a certain number of failed processing
      attempts.
    &lt;/p&gt;
    &lt;br /&gt;

    &lt;p&gt;
      Specifically, the &lt;code&gt;RedrivePolicy&lt;/code&gt; contains two key components:
    &lt;/p&gt;
    &lt;br /&gt;

    &lt;p&gt;
      &amp;#8226; &lt;code&gt;maxReceiveCount&lt;/code&gt; : This is the maximum number of times
      a consumer can attempt to receive and process a message before it is sent
      to the DLQ. When a consumer gets a message but fails to process it (due to
      an error, timeout, or explicit rejection), the receive count for that
      message is increased. When the receive count hits &lt;b&gt;maxReceiveCount&lt;/b&gt;,
      the message is automatically transferred from the main queue to the
      related DLQ.
    &lt;/p&gt;
    &lt;br /&gt;

    &lt;p&gt;
      &amp;#8226; &lt;code&gt;deadLetterTargetArn&lt;/code&gt; : This is the Amazon Resource
      Name (ARN) of the dead-letter queue where the message will be sent after
      exceeding the &lt;b&gt;maxReceiveCount&lt;/b&gt;. This clearly identifies the
      destination queue for failed messages.
    &lt;/p&gt;
    &lt;br /&gt;
  &lt;/div&gt;
&lt;/section&gt;

&lt;!--  create dead letter queue using amazon console  --&gt;
&lt;section&gt;
  &lt;h2&gt;Creating and Configuring Dead-Letter Queues using the Amazon Console&lt;/h2&gt;
  &lt;hr /&gt;

  &lt;p&gt;
    For those without AWS CLI access, the AWS Management Console provides an
    alternative method for creating and configuring dead-letter queues in Amazon
    SQS.
  &lt;/p&gt;
  &lt;br /&gt;

  &lt;section&gt;
    &lt;h3&gt;Creating a Dead-Letter Queue&lt;/h3&gt;
    &lt;p&gt;
      In the &lt;a href="https://aws.amazon.com/console/" target="_blank" rel="nofollow"&gt;(getButton) #text=(Amazon Console) #icon=(link) #color=(#d35400)&lt;/a&gt;, navigate to the SQS service by searching for "&lt;b&gt;SQS&lt;/b&gt;,"
      as shown in the following screenshot.
    &lt;/p&gt;
    &lt;br /&gt;

    &lt;div class="separator" style="clear: both;"&gt;
      &lt;a
        href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRa6RB_S2NRp98ojWNFdCS9slR37Lg4ENEKV0aYGM5HVi7wxaBcdPu0cDqkgBcwvqoK8jMH8PnnFLRsNEBg0wPlDSXwF7fzuoh5fAy18AFkM63-mV3hwYRibuJAtdbBKaQvwPHoNHeOTLgN8daE_QOkDzxiWVJVxM3pK8smg5AMKoVWuK8qQ6haT1NFDVg/s1600/1-sqs-queue-search.png"
        style="display: block; padding: 1em 0; text-align: center; "
        &gt;&lt;img
          alt="In the Amazon console, navigate to the SQS service by searching for SQS, as shown in the this screenshot."
          border="0"
          data-original-height="1179"
          data-original-width="1861"
          src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRa6RB_S2NRp98ojWNFdCS9slR37Lg4ENEKV0aYGM5HVi7wxaBcdPu0cDqkgBcwvqoK8jMH8PnnFLRsNEBg0wPlDSXwF7fzuoh5fAy18AFkM63-mV3hwYRibuJAtdbBKaQvwPHoNHeOTLgN8daE_QOkDzxiWVJVxM3pK8smg5AMKoVWuK8qQ6haT1NFDVg/s1600/1-sqs-queue-search.png"
      /&gt;&lt;/a&gt;
    &lt;/div&gt;

    &lt;p&gt;
      Click "&lt;b&gt;Create queue&lt;/b&gt;" to begin creating your first queue. We'll start by
      creating the dead-letter queue.
    &lt;/p&gt;
    &lt;br /&gt;

    &lt;div class="separator" style="clear: both;"&gt;
      &lt;a
        href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYW7s8Si9B0GubUX_F1XBT9yWz1vtKxqiMJYmynYYS-nUolidBGYOBVaPck_oD6T7mKtQiEk5YpH8eNyqdTx9EiEA0BZ7eKKrV7oH96_Tjn055C4u_HjUqHbQeVTA4R7znKIobPGxvbebp75ciNgyedI9psJ_qVkqcmZBMWRRWxeDb9W0CptqhzAFLimsF/s1600/2-main-sqs-queue-page.png"
        style="display: block; padding: 1em 0; text-align: center; "
        &gt;&lt;img
          alt="create queue button to begin creting sqs queue"
          border="0"
          data-original-height="1207"
          data-original-width="2491"
          src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYW7s8Si9B0GubUX_F1XBT9yWz1vtKxqiMJYmynYYS-nUolidBGYOBVaPck_oD6T7mKtQiEk5YpH8eNyqdTx9EiEA0BZ7eKKrV7oH96_Tjn055C4u_HjUqHbQeVTA4R7znKIobPGxvbebp75ciNgyedI9psJ_qVkqcmZBMWRRWxeDb9W0CptqhzAFLimsF/s1600/2-main-sqs-queue-page.png"
      /&gt;&lt;/a&gt;
    &lt;/div&gt;

    &lt;p&gt;
      We're creating a standard queue called &lt;code&gt;dead-letter-queue&lt;/code&gt;. The
      same process applies to FIFO queues.
    &lt;/p&gt;
    &lt;br /&gt;

    &lt;div class="separator" style="clear: both;"&gt;
      &lt;a
        href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCaJ7MLHPoJR1XYBfht1exWRizSaiv-NxTAONEfOo2MMy2bN8ICIC4k98wST_714jZAXHGrJj2gbcnBhY4xBsRA0K_anXYg92inH02AaW2DFGRBwDGP6hyDSWND3vxDjJzUdGAq7xw3ckDCrKNglb3JeRQCDkjTd0xEszSUmw3m9Fmp3_yobrYRPZtB4RJ/s1600/3-create-queue-dead-letter.png"
        style="display: block; padding: 1em 0; text-align: center; "
        &gt;&lt;img
          alt="standard aws sqs queue"
          border="0"
          data-original-height="982"
          data-original-width="2060"
          src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCaJ7MLHPoJR1XYBfht1exWRizSaiv-NxTAONEfOo2MMy2bN8ICIC4k98wST_714jZAXHGrJj2gbcnBhY4xBsRA0K_anXYg92inH02AaW2DFGRBwDGP6hyDSWND3vxDjJzUdGAq7xw3ckDCrKNglb3JeRQCDkjTd0xEszSUmw3m9Fmp3_yobrYRPZtB4RJ/s1600/3-create-queue-dead-letter.png"
      /&gt;&lt;/a&gt;
    &lt;/div&gt;

    &lt;p&gt;
      Several optional configurations are available, but we will proceed with
      the default settings for this example.
    &lt;/p&gt;
    &lt;br /&gt;

    &lt;div class="separator" style="clear: both;"&gt;
      &lt;a
        href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnpoaK7Ftb4-FGKp50Pnjnvmwwio7SqhluSlqEaYBjbQs4EEDMJdeCQB41VZEIOpaA_A24KFAxTfQsKNiROcoxcZiWXIOPh5qwbVuqTuzA4pw-PMCL0BZUIEzj1pE1p5laXqefBstUcqnXxYmMeXfKdjk6EXw57pe_5SEVngw7pu87RF5rR8pAvxe8N9co/s1600/4-configuration.png"
        style="display: block; padding: 1em 0; text-align: center; "
        &gt;&lt;img
          alt="configuration tab"
          border="0"
          data-original-height="675"
          data-original-width="1962"
          src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnpoaK7Ftb4-FGKp50Pnjnvmwwio7SqhluSlqEaYBjbQs4EEDMJdeCQB41VZEIOpaA_A24KFAxTfQsKNiROcoxcZiWXIOPh5qwbVuqTuzA4pw-PMCL0BZUIEzj1pE1p5laXqefBstUcqnXxYmMeXfKdjk6EXw57pe_5SEVngw7pu87RF5rR8pAvxe8N9co/s1600/4-configuration.png"
      /&gt;&lt;/a&gt;

      &lt;p&gt;
        The queue creation process is finalized by clicking the "&lt;b&gt;Create queue&lt;/b&gt;"
        button located at the bottom of the screen.
      &lt;/p&gt;
      &lt;br /&gt;
    &lt;/div&gt;
  &lt;/section&gt;

  &lt;section&gt;
    &lt;h3&gt;Creating a Standard SQS Queue with Dead-Letter Queue Configuration&lt;/h3&gt;

    &lt;p&gt;
      Let's proceed to create the main queue with the dead-letter queue
      configuration. Since the dead-letter queue is a standard queue, we will
      also create a standard main queue in this example.
    &lt;/p&gt;
    &lt;br /&gt;

    &lt;div class="separator" style="clear: both;"&gt;
      &lt;a
        href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYcbp3Thmw0754Jm6hex2R0lxhyUdS6RXdH4LGD7Vrjp-XC3SKj-taumwYtB3j5lQsLNhVZZu4IdZ1yMeR14Ks3EnfH0y1-YJsT8JsZqOzUBbUUVOfvPc6XH8eM7dqqglLqnFzJkuWCs-p8Ud_9rPGHOlXyKxBDIyE20T8PPh3UtXKKRspWQJfY0-Fu4SU/s1600/5-main-queue.png"
        style="display: block; padding: 1em 0; text-align: center; "
        &gt;&lt;img
          alt="standard aws sqs queue"
          border="0"
          data-original-height="973"
          data-original-width="2038"
          src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYcbp3Thmw0754Jm6hex2R0lxhyUdS6RXdH4LGD7Vrjp-XC3SKj-taumwYtB3j5lQsLNhVZZu4IdZ1yMeR14Ks3EnfH0y1-YJsT8JsZqOzUBbUUVOfvPc6XH8eM7dqqglLqnFzJkuWCs-p8Ud_9rPGHOlXyKxBDIyE20T8PPh3UtXKKRspWQJfY0-Fu4SU/s1600/5-main-queue.png"
      /&gt;&lt;/a&gt;
    &lt;/div&gt;

    &lt;p&gt;
      Enabling the dead-letter queue for this main queue is accomplished by
      providing the ARN of the designated DLQ.
    &lt;/p&gt;
    &lt;br /&gt;

    &lt;div class="separator" style="clear: both;"&gt;
      &lt;a
        href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSZQVNlnYRrgyIyq_XPgsUtkWozQcED-jrDNQkB_3CN8sYqVuwG-IaW0mG0FOBI6izPMdWPSLe9C-JW6hGgiw7hUwXx_mwGpdyWcRWlLEZQP-OmbCwxJoDZa-OHdksfqbnOLgU1GuIn-JJnCPd5IECJg0e3osF1IS_2MIyhZi4EskYmAulnwFU1gmPtcxZ/s1600/6-enable-dead-letter-queue-on-main.png"
        style="display: block; padding: 1em 0; text-align: center; "
        &gt;&lt;img
          alt=""
          border="0"
          data-original-height="675"
          data-original-width="1322"
          src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSZQVNlnYRrgyIyq_XPgsUtkWozQcED-jrDNQkB_3CN8sYqVuwG-IaW0mG0FOBI6izPMdWPSLe9C-JW6hGgiw7hUwXx_mwGpdyWcRWlLEZQP-OmbCwxJoDZa-OHdksfqbnOLgU1GuIn-JJnCPd5IECJg0e3osF1IS_2MIyhZi4EskYmAulnwFU1gmPtcxZ/s1600/6-enable-dead-letter-queue-on-main.png"
      /&gt;&lt;/a&gt;
    &lt;/div&gt;

    &lt;p&gt;
      The queue creation process is finalized by clicking the "&lt;b&gt;Create queue&lt;/b&gt;"
      button located at the bottom of the screen.
    &lt;/p&gt;
    &lt;br /&gt;
  &lt;/section&gt;
&lt;/section&gt;


&lt;section&gt;
  &lt;h2&gt;Conclusion&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;You now have the tools to effectively manage message processing errors in your Amazon SQS queues. Whether you prefer the visual interface of the AWS Management Console or the scripting power of the AWS CLI, you can now seamlessly integrate DLQs into your architecture.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;This ensures that transient errors don't lead to permanent data loss and allows you to investigate and resolve underlying issues more effectively.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;Remember to regularly monitor your DLQs and implement appropriate alerting mechanisms to proactively address any recurring problems.&lt;/p&gt;&lt;br/&gt;
&lt;/section&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;
</content><link href="https://www.learnjavaskills.in/feeds/906003920259939347/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/12/configure-dead-letter-queue-for-amazon-sqs.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/906003920259939347" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/906003920259939347" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/12/configure-dead-letter-queue-for-amazon-sqs.html" rel="alternate" title="How to configure a Dead-Letter Queue (DLQ) for Amazon SQS" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQPJ2ikXQnfeqISMEF05SeWH8dVmiqDuhjbFLOkm8_mE8CWFh-Oa-WiPO676WVVhcPQZogFGik-jEnAV51EVp1dAJckzZbfw0ODyMTQX_BcFA1uRRFcNDi7KXHlEX1BlvdpPO-0nkEqfNfd5Un1qnqzooMOMR3LeKR42ItRKzH7YRF_euAH-YzKtEtNpAs/s72-c/Dead%20Letter%20Queue%20Thumbnail.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-6389432581421327943</id><published>2024-11-24T20:22:00.000+05:30</published><updated>2024-11-24T20:22:21.175+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">DynamoDB Transactions with TransactWriteItems and TransactGetItems with Spring Boot | LearnJavaSkills</title><content type="html">&lt;p&gt;Amazon DynamoDB is a fully managed NoSQL database service that offers high performance, scalability, and availability for any application. One of its key features that sets it apart from other NoSQL databases is its support for transactions.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Transactions in DynamoDB are a crucial mechanism for ensuring data consistency and integrity in your applications. They allow you to perform multiple operations on multiple items within a single atomic unit, &lt;u&gt;guaranteeing that either all operations are successful or none of them are&lt;/u&gt;.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbN93lu_WGX9FzPDWAm0V-WHh3b-c92sJFXTb76eRJGVKQo9UElR7vVfdUDn9YM3ueXav0xzhPgO-vIyXEZYFQjPEq7xaV4ohwoiHjBHryIEFcnlO3SXpm4dxXcU88hyphenhyphen-eDhw6MyD6WcVQ7bnCIMNlq9VAUm1NYJcyM29SJ2nPU2qgxsBZIFjxSID_8VRW/s1600/transaction-dynamodb-thumbnail.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="AWS DynamoDB Transactions: A Spring Boot Guide thumbnail image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbN93lu_WGX9FzPDWAm0V-WHh3b-c92sJFXTb76eRJGVKQo9UElR7vVfdUDn9YM3ueXav0xzhPgO-vIyXEZYFQjPEq7xaV4ohwoiHjBHryIEFcnlO3SXpm4dxXcU88hyphenhyphen-eDhw6MyD6WcVQ7bnCIMNlq9VAUm1NYJcyM29SJ2nPU2qgxsBZIFjxSID_8VRW/s1600/transaction-dynamodb-thumbnail.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;The two main types of operations supported by DynamoDB transactions are &lt;code&gt;TransactWriteItems&lt;/code&gt; and &lt;code&gt;TransactGetItems&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-dynamodb" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;strike&gt;toc&lt;/strike&gt;

&lt;br/&gt;


&lt;h2&gt;Dependencies&lt;/h2&gt;
&lt;hr&gt;

&lt;pre&gt;&lt;code class="groovy"&gt; ext {
	springCloudAwsVersion = &amp;#39;3.0.0&amp;#39;
 }
 
 dependencies {
	// spring cloud aws BOM(Bill of materials)
	implementation platform(&amp;quot;io.awspring.cloud:spring-cloud-aws-dependencies:${springCloudAwsVersion}&amp;quot;)
	// dynamoDB
	implementation &amp;#39;io.awspring.cloud:spring-cloud-aws-starter-dynamodb&amp;#39;
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;h2&gt;Application Configuration (application.properties)&lt;/h2&gt;
&lt;hr&gt;

&lt;pre&gt;&lt;code class = "properties"&gt; # DynamoDB connection
 spring.cloud.aws.credentials.access-key=
 spring.cloud.aws.credentials.secret-key=
 # Choose your region according to your table. Because I have a DynamoDB table in the ap-south-1 area, I&amp;#39;ve set the endpoint and region.
 spring.cloud.aws.region.static=ap-south-1
 spring.cloud.aws.endpoint=https://dynamodb.ap-south-1.amazonaws.com&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;Want to learn more about efficient data management in DynamoDB? My tutorial on &lt;a href="https://www.learnjavaskills.in/2024/08/dynamodb-batchwriteitem-and-batchgetitem-operations.html"&gt;(getButton) #text=(DynamoDB BatchWriteItem and BatchGetItem in Java Spring Boot Applications) #icon=(link) #color=(#35a576)&lt;/a&gt; is a great starting point.(alert-passed)&lt;/blockquote&gt;

&lt;h2&gt;TransactWriteItems API&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;&lt;code&gt;TransactWriteItems&lt;/code&gt; is a synchronous, idempotent operation that allows you to group up to 100 write actions into a single atomic transaction, ensuring either complete success or failure.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;These actions can target up to 100 distinct items across multiple tables within the same region.The aggregate size of the items in the transaction cannot exceed 4 MB&lt;/p&gt;

&lt;blockquote&gt;Unlike BatchWriteItem operations, TransactWriteItems require all included actions to be completed successfully for the entire transaction to be considered successful. With BatchWriteItem, individual actions can succeed or fail independently.(alert-warning)&lt;/blockquote&gt;

&lt;p&gt;You can't target the same item with multiple operations within the same transaction. For example, you can't perform a ConditionCheck and also an Update action on the same item in the same transaction.&lt;/p&gt;

&lt;blockquote&gt;&lt;b&gt;software.amazon.awssdk.services.dynamodb.model.DynamoDbException&lt;/b&gt;: Transaction request cannot include multiple operations on one item(alert-error)&lt;/blockquote&gt;


&lt;p&gt;To illustrate the practical application of all four TransactWriteItems operations, we'll use an e-commerce scenario. I have four tables: &lt;b&gt;customer&lt;/b&gt;, &lt;b&gt;orders&lt;/b&gt;, &lt;b&gt;products&lt;/b&gt;, and &lt;b&gt;cart&lt;/b&gt;, and we'll simulate a customer placing an order.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;ConditionCheck: Ensuring Data Integrity with Conditional Writes&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ConditionCheck&lt;/code&gt; Determines if an item exists or meets certain criteria.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;When we need to determine if a certain condition is true, it's often best to use condition checking. For example, before allowing a customer to place an order, I'll check if their account is active.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; private ConditionCheck customerExistsConditionCheck() {
        // customer table partition key and sort key
        HashMap&amp;lt;String, AttributeValue&amp;gt; customerKey = new HashMap&amp;lt;&amp;gt;();
        customerKey.put(&amp;quot;customer_id&amp;quot;, AttributeValue.fromS(&amp;quot;c_123&amp;quot;)); // partition key
        customerKey.put(&amp;quot;email&amp;quot;, AttributeValue.fromS(&amp;quot;dummy@email.com&amp;quot;)); // sort key

        // expression attribute values is fill the expected values in the query placeholder.
        Map&amp;lt;String, AttributeValue&amp;gt; customerExpressionAttributeValue = new HashMap&amp;lt;&amp;gt;();
        customerExpressionAttributeValue.put(&amp;quot;:expected_active_status&amp;quot;, AttributeValue.fromBool(true));

        // verify attribute &amp;#39;active&amp;#39; exist in the items and active status must be true.
        String attribute = &amp;quot;active&amp;quot;;
        return ConditionCheck.builder()
                .tableName(&amp;quot;customer&amp;quot;)
                .key(customerKey)
                .conditionExpression(&amp;quot;attribute_exists(&amp;quot; + attribute + &amp;quot;)&amp;quot;)
                .conditionExpression(&amp;quot;active = :expected_active_status&amp;quot;)
                .expressionAttributeValues(customerExpressionAttributeValue)
                .build();
    }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


    &lt;h4&gt;tableName() method &lt;/h4&gt;
    &lt;p&gt;The tableName method in the ConditionCheck class of the AWS SDK for Java is primarily used to specify the DynamoDB table that you want to perform the conditional operation on&lt;/p&gt;
  &lt;br/&gt;
  
  
    &lt;h4&gt;key() method&lt;/h4&gt;
    &lt;p&gt;The ConditionCheck class's key method accepts a &lt;u&gt;partition key and a sort key&lt;/u&gt; as parameters.&lt;/p&gt;
  &lt;br/&gt;
  
  
    &lt;h4&gt;conditionExpression() method &lt;/h4&gt;
    &lt;p&gt;The conditionExpression method in the ConditionCheck class of the AWS SDK for Java is used to specify a logical expression that must be satisfied for a DynamoDB operation to succeed.&lt;/p&gt;&lt;br/&gt;

	&lt;p&gt;The conditionExpression is typically combined with &lt;u&gt;withExpressionAttributeValues and withExpressionAttributeNames&lt;/u&gt; to define the specific attributes and values to be used in the expression.&lt;/p&gt;
  &lt;br/&gt;
  
  
    &lt;h4&gt;expressionAttributeValues() method&lt;/h4&gt;
    &lt;p&gt;The expressionAttributeValues method in the ConditionCheck class of the AWS SDK is used to define the actual values that will be used in the condition expression.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;When you create a condition expression, you often use placeholders for attribute values. The expressionAttributeValues method allows you to map these placeholders to their corresponding actual values. This ensures that the condition expression is evaluated correctly with the correct data.&lt;/p&gt;
  &lt;br/&gt;


 &lt;h4&gt;Functions in DynamoDB&lt;/h4&gt;
      
   &lt;p&gt;&lt;code&gt;attribute_exists&lt;/code&gt;: True if the item contains the attribute specified by path. &lt;br/&gt;

     &lt;b&gt;Example&lt;/b&gt;: Check whether an item in the Product table has a side view picture.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;attribute_exists (#Pictures.#SideView)&lt;/code&gt;&lt;/pre&gt;
&lt;br/&gt;
      
      &lt;p&gt;To explore DynamoDB functions in depth, check out &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html"&gt;&lt;u&gt;Condition and filter expressions, operators, and functions&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Put: Adding or Updating Items&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Put&lt;/code&gt; Initiates a &lt;b&gt;PutItem&lt;/b&gt; operation to create a new item or update an existing one, either unconditionally or based on specified conditions&lt;/p&gt;&lt;br/&gt;


&lt;pre&gt;&lt;code class = "java"&gt; private Put placeOrder() {
        // create a map with key value pair to insert a record into order table
        Map&amp;lt;String, AttributeValue&amp;gt; orderItems = new HashMap&amp;lt;&amp;gt;();
        orderItems.put(&amp;quot;order_id&amp;quot;, AttributeValue.fromS(&amp;quot;od_123&amp;quot;)); // partition key
        orderItems.put(&amp;quot;product_id&amp;quot;, AttributeValue.fromS(&amp;quot;p_123&amp;quot;)); // sort key
        orderItems.put(&amp;quot;customer_id&amp;quot;, AttributeValue.fromS(&amp;quot;c_123&amp;quot;));
        orderItems.put(&amp;quot;total_amount&amp;quot;, AttributeValue.fromS(&amp;quot;101&amp;quot;));
        orderItems.put(&amp;quot;status&amp;quot;, AttributeValue.fromS(&amp;quot;CONFIRM&amp;quot;));

        return Put.builder()
                .tableName(&amp;quot;orders&amp;quot;)
                .item(orderItems)
                // An optional parameter that returns the item attributes for an UpdateItem operation that failed a condition check.
                .returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
                .build();
    }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;


&lt;h4&gt;item() method&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;item&lt;/code&gt;: The items method takes a Map&amp;lt;String, AttributeValue&amp;gt; as an argument. This map represents the attributes and their corresponding values that you want to associate with the item.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&amp;#8226; &lt;b&gt;Key&lt;/b&gt;: The key in the map represents the attribute name.&lt;/p&gt;
&lt;p&gt;&amp;#8226; &lt;b&gt;Value&lt;/b&gt;: The value is an AttributeValue object that contains the actual value for the attribute. This value can be of various types, &lt;u&gt;such as a string, number, or list&lt;/u&gt;.&lt;/p&gt;&lt;br/&gt;


&lt;h4&gt;ReturnValuesOnConditionCheckFailure() method&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;ReturnValuesOnConditionCheckFailure&lt;/code&gt;: The &lt;u&gt;ReturnValuesOnConditionCheckFailure&lt;/u&gt; parameter determines what DynamoDB should do when a conditional write fails. Typically, if a condition isn't met, DynamoDB will only report an error.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;However, with &lt;u&gt;ReturnValuesOnConditionCheckFailure&lt;/u&gt;, you can choose to have DynamoDB return the item's original attributes before the write attempt failed. You have two options:&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#8226; &lt;b&gt;ALL_OLD&lt;/b&gt;: Returns all attributes of the item.&lt;/p&gt;
&lt;p&gt;&amp;#8226; &lt;b&gt;NONE&lt;/b&gt;: Returns no data (the default).&lt;/p&gt; &lt;br/&gt;



&lt;h3&gt;Update: Modifying Existing Items&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Update&lt;/code&gt; Performs an &lt;b&gt;UpdateItem&lt;/b&gt; operation to modify an existing item or create a new one if it doesn't exist. This action allows you to conditionally add, delete, or update attributes.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; private Update updateProductQuantity() {

        // products table partition key and sort key
        HashMap&amp;lt;String, AttributeValue&amp;gt; productsKey = new HashMap&amp;lt;&amp;gt;();
        productsKey.put(&amp;quot;product_id&amp;quot;, AttributeValue.fromS(&amp;quot;p_123&amp;quot;)); // partition key
        productsKey.put(&amp;quot;name&amp;quot;, AttributeValue.fromS(&amp;quot;laptop&amp;quot;)); // sort key

        // expression attribute values is fill the expected values in the query placeholder.
        Map&amp;lt;String, AttributeValue&amp;gt; productsExpressionAttributeValue = new HashMap&amp;lt;&amp;gt;();
        productsExpressionAttributeValue.put(&amp;quot;:available_quantity&amp;quot;, AttributeValue.fromN(&amp;quot;11&amp;quot;));
        productsExpressionAttributeValue.put(&amp;quot;:expected_product_status&amp;quot;, AttributeValue.fromBool(true));

        return Update.builder()
                .tableName(&amp;quot;products&amp;quot;)
                .key(productsKey)
                // query - set quantity to 11
                .updateExpression(&amp;quot;SET quantity = :available_quantity&amp;quot;)
                // query - just like a where clause
                .conditionExpression(&amp;quot;product_status = :expected_product_status&amp;quot;)
                // provide actual values of placeholder used in the query i.e., available_quantity and  expected_product_status
                .expressionAttributeValues(productsExpressionAttributeValue)
                // An optional parameter that returns the item attributes for an UpdateItem operation that failed a condition check.
                .returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
                .build();
    }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h4&gt;updateExpression() method&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;updateExpression&lt;/code&gt; method in the Update class of the AWS SDK for DynamoDB is used to specify how you want to modify an existing item in a table. It allows you to:&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#8226; &lt;b&gt;Set&lt;/b&gt; new values for attributes.&lt;/p&gt;
&lt;p&gt;&amp;#8226; &lt;b&gt;Add&lt;/b&gt; values to sets or numbers.&lt;/p&gt;
&lt;p&gt;&amp;#8226; &lt;b&gt;Remove&lt;/b&gt; attributes or elements from sets.&lt;/p&gt;
&lt;p&gt;&amp;#8226; &lt;b&gt;Delete&lt;/b&gt; elements from lists or maps&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;You can use placeholders in your &lt;u&gt;updateExpression&lt;/u&gt; and then define the corresponding values using the &lt;code&gt;expressionAttributeValues&lt;/code&gt; method. This provides a flexible way to update items based on specific conditions or requirements.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;Delete: Removing Items from the Table&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Delete&lt;/code&gt; Performs a &lt;b&gt;DeleteItem&lt;/b&gt; operation on a specific item within a table based on its primary key.&lt;/p&gt;&lt;br/&gt;


&lt;pre&gt;&lt;code class = "java"&gt; private Delete deleteCartEntry() {

        // cart table partition key and sort key
        HashMap&amp;lt;String, AttributeValue&amp;gt; cartKey = new HashMap&amp;lt;&amp;gt;();
        cartKey.put(&amp;quot;cart_id&amp;quot;, AttributeValue.fromS(&amp;quot;ct_123&amp;quot;)); // partition key
        cartKey.put(&amp;quot;product_id&amp;quot;, AttributeValue.fromS(&amp;quot;p_123&amp;quot;)); // sort key

        // expression attribute values is fill the expected values in the query placeholder.
        Map&amp;lt;String, AttributeValue&amp;gt; cartExpressionAttributeValue = new HashMap&amp;lt;&amp;gt;();
        cartExpressionAttributeValue.put(&amp;quot;:expected_quantity&amp;quot;, AttributeValue.fromN(&amp;quot;1&amp;quot;));

        return Delete.builder()
                .tableName(&amp;quot;cart&amp;quot;)
                .key(cartKey)
                // query - just like where clause, here verifying the quantity is equal to 1
                .conditionExpression(&amp;quot;quantity = :expected_quantity&amp;quot;)
                // provide actual values of placeholder used in the query i.e expected_quantity which is 1
                .expressionAttributeValues(cartExpressionAttributeValue)
                // An optional parameter that returns the item attributes for an UpdateItem operation that failed a condition check.
                .returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
                .build();

    }&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;Within the AWS SDK for Java, &lt;u&gt;the ConditionCheck, Put, Update, and Delete classes&lt;/u&gt; &lt;b&gt;found in the software.amazon.awssdk.services.dynamodb.model package&lt;/b&gt;.(alert-success)&lt;/blockquote&gt;

&lt;h3&gt;Executing the Transaction&lt;/h3&gt;

&lt;p&gt;Executing transactions in DynamoDB using TransactionWriteItem ensures atomic operations across multiple items.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#8226; Create a list of &lt;code&gt;TransactWriteItem&lt;/code&gt; objects: Each object defines a single write operation (put, update, or delete) on an item.&lt;/p&gt;

&lt;p&gt;&amp;#8226; Execute the transaction: Call the &lt;b&gt;TransactWriteItems&lt;/b&gt; API, passing in the list of &lt;b&gt;TransactWriteItemsRequest&lt;/b&gt; objects.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt;  public void transactionWrite() {

        // Collect Transaction Write in a list
        List&amp;lt;TransactWriteItem&amp;gt; transactionWriteItem = List.of(TransactWriteItem.builder().conditionCheck(customerExistsConditionCheck()).build(),
                TransactWriteItem.builder().put(placeOrder()).build(),
                TransactWriteItem.builder().update(updateProductQuantity()).build(),
                TransactWriteItem.builder().delete(deleteCartEntry()).build());

        // TransactWriteItemRequest
        TransactWriteItemsRequest transactWriteItemsRequest = TransactWriteItemsRequest.builder()
                .transactItems(transactionWriteItem)
                .build();

        // Run the transaction write item
        try
        {
            TransactWriteItemsResponse transactWriteItemsResponse = dynamoDbClient.transactWriteItems(transactWriteItemsRequest);
            System.out.println(&amp;quot;Successfully completed write operation&amp;quot;);
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;A &lt;code&gt;TransactionCanceledException&lt;/code&gt; exception may occur due to any of the following reasons&lt;br/&gt;

  &amp;#8226; When a condition in one of the condition expressions is not met.&lt;br/&gt;
  &amp;#8226; When a transaction validation error occurs because more than one action in the same TransactWriteItems operation targets the same item. &lt;br/&gt;
  &amp;#8226; When a &lt;code&gt;TransactWriteItems&lt;/code&gt; request conflicts with an ongoing &lt;code&gt;TransactWriteItems&lt;/code&gt; operation on one or more items in the &lt;code&gt;TransactWriteItems&lt;/code&gt; request.(alert-error)&lt;/blockquote&gt;


&lt;h2&gt;TransactGetItems API&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;&lt;code&gt;TransactGetItems&lt;/code&gt; efficiently fetches data from multiple DynamoDB tables by combining up to 100 individual Get operations into a single synchronous request.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This allows for retrieving data from a maximum of 100 items across different tables within the same AWS account and Region, provided the total data size doesn't exceed 4 MB.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The &lt;code&gt;Get&lt;/code&gt; actions are performed atomically so that either all of them succeed or all of them fail:&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&lt;code&gt;Get&lt;/code&gt; — Initiates a GetItem operation to retrieve a set of attributes for the item with the given primary key. If no matching item is found, Get does not return any data.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;To illustrate the TransactGetItems operation, I will retrieve data from both the &lt;u&gt;customer and orders tables in the following example&lt;/u&gt;.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt;  public void transactionRead() {
        // customer&amp;#39;s partition key and sort key
        HashMap&amp;lt;String, AttributeValue&amp;gt; customerKey = new HashMap&amp;lt;&amp;gt;();
        customerKey.put(&amp;quot;customer_id&amp;quot;, AttributeValue.fromS(&amp;quot;c_123&amp;quot;)); // partition Key
        customerKey.put(&amp;quot;email&amp;quot;, AttributeValue.fromS(&amp;quot;dummy@email.com&amp;quot;)); // sort key

        // order&amp;#39;s partition key and sort key
        Map&amp;lt;String, AttributeValue&amp;gt; orderKey = new HashMap&amp;lt;&amp;gt;();
        orderKey.put(&amp;quot;order_id&amp;quot;, AttributeValue.fromS(&amp;quot;od_123&amp;quot;)); // partition Key
        orderKey.put(&amp;quot;product_id&amp;quot;, AttributeValue.fromS(&amp;quot;p_123&amp;quot;)); // sort key

        // Fetch all the customer whose partition key and sort key match
        Get customersGet = Get.builder()
                .tableName(&amp;quot;customer&amp;quot;)
                .key(customerKey)
                .build();

        // Fetch all the orders whose partition key and sort key match
        Get ordersGet = Get.builder()
                .tableName(&amp;quot;orders&amp;quot;)
                .key(orderKey)
                .build();

        // Collect all the read operation in a list of TransactGetItem
        List&amp;lt;TransactGetItem&amp;gt; transactGetItemList = List.of(TransactGetItem.builder().get(customersGet).build(),
                TransactGetItem.builder().get(ordersGet).build());

        // TransactGetItemRequest
        TransactGetItemsRequest transactGetItemsRequest = TransactGetItemsRequest.builder()
                .transactItems(transactGetItemList)
                .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
                .build();

        // Run the transactGetItem operation
        try {
            TransactGetItemsResponse transactGetItemsResponse = dynamoDbClient.transactGetItems(transactGetItemsRequest);
            List&amp;lt;ItemResponse&amp;gt; responses = transactGetItemsResponse.responses();
            if (Objects.nonNull(responses) &amp;amp;&amp;amp; !responses.isEmpty()) {
                responses.stream()
                        .flatMap(response -&amp;gt; response.item().entrySet().stream())
                        .forEach(entry -&amp;gt; {
                            System.out.println(&amp;quot;attribute: &amp;quot; + entry.getKey() + &amp;quot; value: &amp;quot; + entry.getValue());
                        } );
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;Read transactions are unsuccessful in the following cases:&lt;br/&gt;
  &amp;#8226; When a &lt;code&gt;TransactGetItems&lt;/code&gt; request conflicts with an ongoing &lt;code&gt;TransactWriteItems&lt;/code&gt; operation on one or more items in the &lt;code&gt;TransactGetItems&lt;/code&gt; request. In this case, the request fails with a &lt;u&gt;TransactionCanceledException&lt;/u&gt;.(alert-error)&lt;/blockquote&gt;

&lt;h2&gt;Conclusion: Leveraging TransactWriteItems and TransactGetItems for Robust DynamoDB Transactions&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;This article has demonstrated the effective use of &lt;u&gt;TransactWriteItems and TransactGetItems&lt;/u&gt; to execute complex transactions within DynamoDB.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;By understanding the core concepts, best practices, and potential limitations, developers can confidently implement atomic operations to maintain data integrity and consistency in their applications.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Enhance your DynamoDB table's performance and lower operational costs by implementing &lt;a href="https://www.learnjavaskills.in/2024/11/dynamodb-table-ttl-setting.html"&gt;(getButton) #text=(DynamoDB's Time to Live for Automatic Data Deletion) #icon=(link) #color=(#35a576)&lt;/a&gt; feature.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-dynamodb" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;

</content><link href="https://www.learnjavaskills.in/feeds/6389432581421327943/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/09/dynamodb-transactions.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/6389432581421327943" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/6389432581421327943" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/09/dynamodb-transactions.html" rel="alternate" title="DynamoDB Transactions with TransactWriteItems and TransactGetItems with Spring Boot | LearnJavaSkills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbN93lu_WGX9FzPDWAm0V-WHh3b-c92sJFXTb76eRJGVKQo9UElR7vVfdUDn9YM3ueXav0xzhPgO-vIyXEZYFQjPEq7xaV4ohwoiHjBHryIEFcnlO3SXpm4dxXcU88hyphenhyphen-eDhw6MyD6WcVQ7bnCIMNlq9VAUm1NYJcyM29SJ2nPU2qgxsBZIFjxSID_8VRW/s72-c/transaction-dynamodb-thumbnail.png" width="72"/><thr:total>0</thr:total><georss:featurename>India</georss:featurename><georss:point>20.593684 78.96288</georss:point><georss:box>-7.7165498361788458 43.80663 48.903917836178849 114.11913</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-3980350946318104955</id><published>2024-11-24T20:11:00.000+05:30</published><updated>2024-11-24T20:11:06.074+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><title type="text">How to Enable Time-to-Live (TTL) for Automatic Data Deletion in Amazon DynamoDB Table</title><content type="html">&lt;p&gt;By leveraging DynamoDB's Time-to-Live (TTL) feature, you can implement a cost-effective strategy for automated data retention. By setting an expiration timestamp for each item, DynamoDB will automatically delete it once the specified time has elapsed.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This process is transparent to the application and does not require additional write capacity units.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Enabling Time to Live (TTL) on a DynamoDB table is easy. You can do this using the AWS Management Console, AWS CLI, or the AWS API. The AWS Console offers the most user-friendly experience.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnijUbRdr0VtxpahEmOYp-Cnd37UxWoP-lPNof-PzZoK8CFMqSWEchruGH4H0N1ugPa02985-heI77HmnpmGJzpHnPa-PaDGu0PcdLrciz_km7VHiNPMgS6q1ydhD5nz-Ad3bco9sfmk1sPbcRKdMf6u6H2uaV4WEZ7GisW8ZsROyIF7Uz-NBSxccyodf0/s1600/Thumbnail%20Image.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Thumbnail Image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnijUbRdr0VtxpahEmOYp-Cnd37UxWoP-lPNof-PzZoK8CFMqSWEchruGH4H0N1ugPa02985-heI77HmnpmGJzpHnPa-PaDGu0PcdLrciz_km7VHiNPMgS6q1ydhD5nz-Ad3bco9sfmk1sPbcRKdMf6u6H2uaV4WEZ7GisW8ZsROyIF7Uz-NBSxccyodf0/s1600/Thumbnail%20Image.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;strike&gt;toc&lt;/strike&gt;&lt;br/&gt;

&lt;h2&gt;Why Time to Live (TTL) is Essential for DynamoDB Performance&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;While you can manually delete items from your DynamoDB table using various methods, configuring TTL offers significant advantages in terms of performance and cost-effectiveness.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Manual deletion operations, regardless of the method used, consume write throughput capacity. This can be particularly expensive when dealing with large numbers of items.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;TTL, however, enables automatic item deletion without consuming any write throughput, leading to substantial savings.&lt;/p&gt;

&lt;blockquote&gt;Please note that DynamoDB can take up to 48 hours or more to fully process and delete items marked for expiration.(alert-warning)&lt;/blockquote&gt;

&lt;h2&gt;Enable Time to Live (TTL) using the AWS CLI&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;The most straightforward approach to enable Time to Live (TTL) on a DynamoDB table is through the AWS CLI. I'll apply this to my &lt;code&gt;session_data&lt;/code&gt; table, utilizing the &lt;code&gt;expires_at&lt;/code&gt; attribute to automatically expire outdated records.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "bash"&gt; aws dynamodb update-time-to-live \ 
 --table-name session_data \ 
 --time-to-live-specification "Enabled=true, AttributeName=expires_at"&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;p&gt;The following output will be displayed after executing the AWS CLI command above.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "json"&gt; {
    &amp;#x22;TimeToLiveSpecification&amp;#x22;: {
        &amp;#x22;Enabled&amp;#x22;: true,
        &amp;#x22;AttributeName&amp;#x22;: &amp;#x22;expires_at&amp;#x22;
    }
  }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;


&lt;p&gt;If you missed the previous output, you can alternatively describe the TTL configuration for a DynamoDB table to retrieve the information.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "bash"&gt; aws dynamodb describe-time-to-live --table-name session_data&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Enable Time to Live (TTL) using the AWS console&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;To leverage DynamoDB's automatic item deletion feature, you need to add a &lt;code&gt;timestamp&lt;/code&gt; attribute of type &lt;code&gt;Number&lt;/code&gt; to your table.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The timestamp value should be in &lt;u&gt;Unix epoch time format&lt;/u&gt;, which represents the number of seconds elapsed since January 1, 1970 UTC. DynamoDB exclusively supports this format for automatic TTL.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;I'll leverage an existing DynamoDB table named &lt;code&gt;session_data&lt;/code&gt; for this exercise. The &lt;code&gt;expire_at&lt;/code&gt; attribute within this table will be used to set up Time to Live (TTL) and automate item deletion.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisrl6f3LdyzHYkoUGszkLTeZ8Npp-kObhHBzb1pPoCDghOphtvAlG-AURsAzeApbDQvvejPKQtq6CvhrVambP3cyow9vJsCu1sc-KvRvRr42z7QOtbM_UqBv10Gxd73UmW4oB5rRhxi_X7TRzvoEpszLcRXPXajJzGx3GVqDVeMb85HUB7dV_k1ZcWzbMd/s1600/session_data_table.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="session data table in dynamodb table" border="0" data-original-height="188" data-original-width="2092" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisrl6f3LdyzHYkoUGszkLTeZ8Npp-kObhHBzb1pPoCDghOphtvAlG-AURsAzeApbDQvvejPKQtq6CvhrVambP3cyow9vJsCu1sc-KvRvRr42z7QOtbM_UqBv10Gxd73UmW4oB5rRhxi_X7TRzvoEpszLcRXPXajJzGx3GVqDVeMb85HUB7dV_k1ZcWzbMd/s1600/session_data_table.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;STEP 1:&lt;/b&gt; From the list of available DynamoDB tables, select the table you want to configure for Time to Live (TTL). In my example, I've chosen the &lt;code&gt;session_data&lt;/code&gt; table.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgw_UPV6w04sRCaUe5-dpR71fkUDCvJbyVQbEJH-4K2MmUwVTwue8c-uI9vARLxyBRr9GOBBG-ZEw73q9REk5Pdp1MaGsAp6qvmWSwBayK3hT-F5MjuHEy0XUhap5_7azxMp5rJDivIRu2qRLHrNXUwJDwQkGyyGfQXzv5USMDnlFv83Pe0AaB0JyM4StNP/s1600/session_data_table_overview.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="session data table selected" border="0" data-original-height="523" data-original-width="2282" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgw_UPV6w04sRCaUe5-dpR71fkUDCvJbyVQbEJH-4K2MmUwVTwue8c-uI9vARLxyBRr9GOBBG-ZEw73q9REk5Pdp1MaGsAp6qvmWSwBayK3hT-F5MjuHEy0XUhap5_7azxMp5rJDivIRu2qRLHrNXUwJDwQkGyyGfQXzv5USMDnlFv83Pe0AaB0JyM4StNP/s1600/session_data_table_overview.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;STEP 2:&lt;/b&gt; Select "&lt;b&gt;Update Setting&lt;/b&gt;" from the "&lt;b&gt;Actions&lt;/b&gt;" dropdown menu, as shown in the screenshot.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1NwLw0b__g1nrJHW-9s20u95QA-9XokpXUIzoRskpIEiBq3L1-B_ZC_v5eyl7hjXa5Vx3XSSV5CCGFJypl8fL6b0FdbgUYm0mLGlbCfQSqsVmWar8RZ88qHBnBiqp9RrhooXBcE2q2T_PzpjcFv-6KTUCl0ravYWsU9yAyn73VsQo080K3GHghP2b09fg/s1600/action_update_satting.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Select Update Setting from Actions drop down button" border="0" data-original-height="514" data-original-width="2278" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1NwLw0b__g1nrJHW-9s20u95QA-9XokpXUIzoRskpIEiBq3L1-B_ZC_v5eyl7hjXa5Vx3XSSV5CCGFJypl8fL6b0FdbgUYm0mLGlbCfQSqsVmWar8RZ88qHBnBiqp9RrhooXBcE2q2T_PzpjcFv-6KTUCl0ravYWsU9yAyn73VsQo080K3GHghP2b09fg/s1600/action_update_satting.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;STEP 3:&lt;/b&gt; Once the DynamoDB table configuration page opens, you'll see the "&lt;b&gt;Overview&lt;/b&gt;" section selected by default. Click the "&lt;b&gt;Additional settings&lt;/b&gt;" button located in the top-right corner (highlighted in red).&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2KufC7F5_dF7jyQ0HX7BAYzFgpP7ZsHajgBit3xq0h6SK_Tpga5T4VddxzFMG2dTApXWrVZrRsOh62K4gpiIc9M-TFqMRtihecKT-sVojzELFdrfz-RICrpj9Sb3VrvS5qEMKpCsmpYaSV6B_yvun81wIUyMRgc8w2ECVTl9F4ntnCD696buv16KgEyth/s1600/additional_settings.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Session data table' overview sections" border="0" data-original-height="806" data-original-width="2275" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2KufC7F5_dF7jyQ0HX7BAYzFgpP7ZsHajgBit3xq0h6SK_Tpga5T4VddxzFMG2dTApXWrVZrRsOh62K4gpiIc9M-TFqMRtihecKT-sVojzELFdrfz-RICrpj9Sb3VrvS5qEMKpCsmpYaSV6B_yvun81wIUyMRgc8w2ECVTl9F4ntnCD696buv16KgEyth/s1600/additional_settings.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;STEP 4:&lt;/b&gt; Locate the "Time to Live (TTL)" section by scrolling down the page. By default, TTL is disabled. To activate it, click the "&lt;b&gt;Turn On&lt;/b&gt;" button.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC0NiqNK-mPoXwPElhQgPcwHYQpcw2Q7RsrLhXiXOLJ-xXgpdAqN0C1At-UYho7pdciHLB2voiYWaRuUe2rxSrb0lFj4oRIAq3VlqY2gUd-WhlXhWEN_XXZXNXYl2x5UiQOALWyA84ewDMTRchuQA_wEN_i_7t893XDGcJrO-umYm6e2jLLU0St-A0NhjY/s1600/ttl.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Tile to Live(TLE) section in additional setting section of session data dynamodb table" border="0" data-original-height="378" data-original-width="2106" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC0NiqNK-mPoXwPElhQgPcwHYQpcw2Q7RsrLhXiXOLJ-xXgpdAqN0C1At-UYho7pdciHLB2voiYWaRuUe2rxSrb0lFj4oRIAq3VlqY2gUd-WhlXhWEN_XXZXNXYl2x5UiQOALWyA84ewDMTRchuQA_wEN_i_7t893XDGcJrO-umYm6e2jLLU0St-A0NhjY/s1600/ttl.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;STEP 5:&lt;/b&gt; In the TTL settings, specify the Number type attribute (e.g., &lt;code&gt;expire_at&lt;/code&gt;) that will be used to determine item expiration based on Unix epoch timestamps.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj68GQgKaTEmjxTpCbD5aL8RItniYThtpuhde7v900_Tj_euTQgPLP_npcs4ZcC7gSG7j-yS6UNeOfoaZ4RnIMQYLZTd1tb9wNyIH-wxbActbZipfkKsxB_tWDjMN6jyOuZ9xJ6haJ9D_yCXnNTMM4HcfNYSp9CQs239iWFHsz0k2zptArbefu0F-UHszYL/s1600/ttl_attribute_configurations.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Time to Live(TTL) Settings" border="0" data-original-height="1123" data-original-width="1326" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj68GQgKaTEmjxTpCbD5aL8RItniYThtpuhde7v900_Tj_euTQgPLP_npcs4ZcC7gSG7j-yS6UNeOfoaZ4RnIMQYLZTd1tb9wNyIH-wxbActbZipfkKsxB_tWDjMN6jyOuZ9xJ6haJ9D_yCXnNTMM4HcfNYSp9CQs239iWFHsz0k2zptArbefu0F-UHszYL/s1600/ttl_attribute_configurations.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;STEP 6:&lt;/b&gt; Optionally, To test the TTL configuration before activating it, click the "&lt;b&gt;Run Preview&lt;/b&gt;" button within the "&lt;b&gt;Preview&lt;/b&gt;" section. This will simulate item deletion based on the specified TTL settings. Once you're satisfied with the preview, click "&lt;b&gt;Turn On TTL&lt;/b&gt;" to enable the configuration.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJskfHEl2JbrK45k_kFRTyh4Gs7QVOcoAs8cFUbFXj25TRG24yGazi5XGTms4FX7pkbPyBpxnV9hUhRhChtmlmuLv9D-M7ruf0aettBZ4l12_-YRwD4K-sTETRSmAsIVef3vMKKLPY0NHQYuUR0Vn5F8aesJwxe-MIaUbQr7JP5VIzMaPnXfVJkpNmVjUr/s1600/ttl_preview_button.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Preview TTL configurations" border="0" data-original-height="835" data-original-width="1598" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJskfHEl2JbrK45k_kFRTyh4Gs7QVOcoAs8cFUbFXj25TRG24yGazi5XGTms4FX7pkbPyBpxnV9hUhRhChtmlmuLv9D-M7ruf0aettBZ4l12_-YRwD4K-sTETRSmAsIVef3vMKKLPY0NHQYuUR0Vn5F8aesJwxe-MIaUbQr7JP5VIzMaPnXfVJkpNmVjUr/s1600/ttl_preview_button.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Once you've activated TTL, the table configuration page will reflect the updated status: "&lt;b&gt;TTL: On&lt;/b&gt;".&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-o0_kaC62Wc4zY79baH5bwqtAhRypqs_o11rlKabiTgKWuRpJVA5q_LiaY3HPPxE1i9mnmgQ7EgO4bItSJYYn_yzM8-HfcEVb4wlMVJc-cRTl6pMTMZ6YNFWeXOPY24KGUWid2Hv3aZ3ALeB7CD104pAMJoW9i_RPChf-RvhDnBzlGRXnRa3qLUSTTsfJ/s1600/ttl_turned_on.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Tile to Live(TTL) turned on" border="0" data-original-height="376" data-original-width="2087" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-o0_kaC62Wc4zY79baH5bwqtAhRypqs_o11rlKabiTgKWuRpJVA5q_LiaY3HPPxE1i9mnmgQ7EgO4bItSJYYn_yzM8-HfcEVb4wlMVJc-cRTl6pMTMZ6YNFWeXOPY24KGUWid2Hv3aZ3ALeB7CD104pAMJoW9i_RPChf-RvhDnBzlGRXnRa3qLUSTTsfJ/s1600/ttl_turned_on.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Time to Live (TTL) is a powerful feature in DynamoDB that can optimize performance and minimize costs. By automatically deleting expired items, TTL reduces storage overhead and improves query performance.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This tutorial has guided you through the process of enabling TTL on your DynamoDB table using the AWS Management Console.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;

</content><link href="https://www.learnjavaskills.in/feeds/3980350946318104955/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/11/dynamodb-table-ttl-setting.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/3980350946318104955" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/3980350946318104955" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/11/dynamodb-table-ttl-setting.html" rel="alternate" title="How to Enable Time-to-Live (TTL) for Automatic Data Deletion in Amazon DynamoDB Table" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnijUbRdr0VtxpahEmOYp-Cnd37UxWoP-lPNof-PzZoK8CFMqSWEchruGH4H0N1ugPa02985-heI77HmnpmGJzpHnPa-PaDGu0PcdLrciz_km7VHiNPMgS6q1ydhD5nz-Ad3bco9sfmk1sPbcRKdMf6u6H2uaV4WEZ7GisW8ZsROyIF7Uz-NBSxccyodf0/s72-c/Thumbnail%20Image.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-1040389967144664053</id><published>2024-10-26T20:57:00.000+05:30</published><updated>2024-10-26T20:57:08.872+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">How to Read Amazon S3 Files Directly in Java/Spring Boot Without Downloading</title><content type="html">&lt;p&gt;Amazon Simple Storage Service (S3) offers a reliable and scalable solution for object storage in the cloud.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;In today's cloud-native world, developers frequently leverage cloud storage services like Amazon S3 to store and manage files efficiently. However, traditional approaches involving downloading files locally can introduce performance bottlenecks.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;In this tutorial, we'll explore how to streamline your workflow and boost application speed by directly reading files from S3, bypassing the need for local file transfers.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-s3" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEip7QrNZCcNIs-NKKvzKw91lkifBzmzwF4v22vEjtF8oDGlbvco4jFP4pNVJqZLhdQ5pJdcWm8v3ikZpsN4LPlkVlr37oh0FxuQSk_Y-3KWyeUAO2TCEf70dSQ2bZB2ZyAJvqHQqZJJDgBfQx4iE-XNReeowulzOKRDqJjulBWqMuqcoAaicEcUu78E_lAA/s1600/Spring%20cloud%20Aws%20S3%20Read%20File%20Into%20Java%20Input%20Stream.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="How to Read Amazon S3 Files Directly in Java/Spring Boot Without Downloading thumbnail image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEip7QrNZCcNIs-NKKvzKw91lkifBzmzwF4v22vEjtF8oDGlbvco4jFP4pNVJqZLhdQ5pJdcWm8v3ikZpsN4LPlkVlr37oh0FxuQSk_Y-3KWyeUAO2TCEf70dSQ2bZB2ZyAJvqHQqZJJDgBfQx4iE-XNReeowulzOKRDqJjulBWqMuqcoAaicEcUu78E_lAA/s1600/Spring%20cloud%20Aws%20S3%20Read%20File%20Into%20Java%20Input%20Stream.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;strike&gt;toc&lt;/strike&gt;
&lt;br/&gt;

&lt;h2&gt;Dependencies&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;To get started with this tutorial, you'll need to add the following dependencies to your Spring Boot project's. This dependency provides the necessary components for interacting with AWS services, including S3.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Gradle&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "groovy"&gt;ext {
    springCloudAwsVersion = &amp;#39;3.0.0&amp;#39;
}

dependencies {
    // spring cloud aws BOM(Bill of materials)
    implementation platform(&amp;quot;io.awspring.cloud:spring-cloud-aws-dependencies:${springCloudAwsVersion}&amp;quot;)
    implementation &amp;#39;io.awspring.cloud:spring-cloud-aws-starter-s3&amp;#39;
    // AWS launched a high level file transfer utility, called Transfer Manager and a CRT based S3 client.
    // The starter automatically configures and registers a software.amazon.awssdk.transfer.s3.S3TransferManager bean if the following dependency is added to the project:
    implementation &amp;#39;software.amazon.awssdk:s3-transfer-manager&amp;#39;
    //Transfer Manager works the best with CRT S3 Client. To auto-configure CRT based S3AsyncClient add following dependency to your project:
    implementation &amp;#39;software.amazon.awssdk.crt:aws-crt&amp;#39;
}&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;h3&gt;Maven&lt;/h3&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;io.awspring.cloud&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-cloud-aws-starter-s3&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
	
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;software.amazon.awssdk&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;s3-transfer-manager&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
	
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;software.amazon.awssdk.crt&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;aws-crt&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;

&amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;io.awspring.cloud&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-cloud-aws-dependencies&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;{project-version}&amp;lt;/version&amp;gt;
            &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
            &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
       &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
&amp;lt;/dependencyManagement&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Configuration and Credentials&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Spring Cloud AWS offers auto-configuration for &lt;code&gt;S3Client&lt;/code&gt;, &lt;code&gt;S3TransferManager&lt;/code&gt;, and &lt;code&gt;S3Template&lt;/code&gt;, making setup a breeze. Here's what you need to add to your &lt;b&gt;&lt;u&gt;application.properties&lt;/u&gt;&lt;/b&gt; file:&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "properties"&gt; # s3 Configuration
 spring.cloud.aws.credentials.access-key=
 spring.cloud.aws.credentials.secret-key=
 # Configures endpoint used by S3Client, I&amp;#39;m woorking in the Asia Pacific (Mumbai) hence, I&amp;#39;ve configure ap-south1 region and endpoint
 spring.cloud.aws.s3.endpoint=https://s3.ap-south-1.amazonaws.com
 spring.cloud.aws.region.static=ap-south-1&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;IAM Permissions for S3 Read Access&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;To grant your IAM user or role permission to read files from S3, you must attach this policy to it.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "json"&gt; {
    &amp;#x22;Version&amp;#x22;: &amp;#x22;2012-10-17&amp;#x22;,
    &amp;#x22;Statement&amp;#x22;: [
        {
            &amp;#x22;Sid&amp;#x22;: &amp;#x22;readAccess&amp;#x22;,
            &amp;#x22;Effect&amp;#x22;: &amp;#x22;Allow&amp;#x22;,
            &amp;#x22;Action&amp;#x22;: &amp;#x22;s3:GetObject&amp;#x22;,
            &amp;#x22;Resource&amp;#x22;: &amp;#x22;arn:aws:s3:::*/*&amp;#x22;
        }
    ]
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Reading S3 Objects Directly into Java Streams&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;&lt;a href="https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html" target="_blank" rel="nofollow"&gt;S3Client&lt;/a&gt; is a Java interface for interacting with Amazon S3. We'll use S3Client to directly read the S3 object into an input stream. Then, we'll use a BufferedReader to process the file line by line.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class = "java"&gt; 
 import software.amazon.awssdk.core.ResponseInputStream;
 import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.GetObjectRequest;
 import software.amazon.awssdk.services.s3.model.GetObjectResponse;

 import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.Arrays;
 import java.util.Objects;

 public void readFileUsingS3Client(String bucketName, String key) {
    try {
        GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();

        ResponseInputStream&amp;#x3C;GetObjectResponse&amp;#x3E; responseResponseInputStream = s3Client.getObject(getObjectRequest);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(responseResponseInputStream));

        String line = &amp;#x22;&amp;#x22;;
        while (Objects.nonNull(line = bufferedReader.readLine())) {
            // Since the file format is CSV, we'll split each line by commas (,) to access individual columns.
            String[] split = line.split(&amp;#x22;,&amp;#x22;);
            System.out.println(&amp;#x22;line: &amp;#x22; + Arrays.toString(split));
        }
    } catch (Exception exception) {
        exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;p&gt;The &lt;code&gt;getObject()&lt;/code&gt; method of &lt;code&gt;S3Client&lt;/code&gt; allows us to read an S3 object directly into a Java input stream. It takes a &lt;code&gt;GetObjectRequest&lt;/code&gt; object as an argument, specifying the &lt;u&gt;bucket name and object key&lt;/u&gt;.&lt;/p&gt;&lt;br/&gt;

&lt;h2&gt;Conclussion&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Reading a file directly from Amazon S3 can not only boost application processing time but also optimize resource utilization, reducing latency and optimizing memory usage by eliminating the need to download files locally&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;To enable public access to your S3 objects without exposing your AWS credentials, explore &lt;a href="https://www.learnjavaskills.in/2024/09/amazon-s3-presigned-url-spring-cloud-aws.html"&gt;(getButton) #text=(how to generate presigned URLs) #icon=(link) #color=(#35a576)&lt;/a&gt; in our comprehensive guide.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-s3" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;

</content><link href="https://www.learnjavaskills.in/feeds/1040389967144664053/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/10/read-s3-file-into-java-input-stream.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/1040389967144664053" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/1040389967144664053" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/10/read-s3-file-into-java-input-stream.html" rel="alternate" title="How to Read Amazon S3 Files Directly in Java/Spring Boot Without Downloading" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEip7QrNZCcNIs-NKKvzKw91lkifBzmzwF4v22vEjtF8oDGlbvco4jFP4pNVJqZLhdQ5pJdcWm8v3ikZpsN4LPlkVlr37oh0FxuQSk_Y-3KWyeUAO2TCEf70dSQ2bZB2ZyAJvqHQqZJJDgBfQx4iE-XNReeowulzOKRDqJjulBWqMuqcoAaicEcUu78E_lAA/s72-c/Spring%20cloud%20Aws%20S3%20Read%20File%20Into%20Java%20Input%20Stream.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-9155813656576735610</id><published>2024-10-26T20:55:00.000+05:30</published><updated>2024-10-26T20:55:23.149+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">Spring Cloud AWS S3 File Download Tutorial: Step-by-Step Guide</title><content type="html">&lt;p&gt;Amazon S3 is a scalable, object-based storage service. Today's enterprise applications often leverage serverless storage solutions like S3 to store and retrieve files efficiently.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This tutorial will demonstrate how to download files or directories from an Amazon S3 bucket using Spring Cloud AWS.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Spring Cloud AWS provides a convenient way to integrate S3 functionality into Spring Boot applications.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;To download files from Amazon S3, you'll first need to &lt;a href="https://www.learnjavaskills.in/2024/10/spring-cloud-aws-s3-file-upload.html"&gt;(getButton) #text=(upload files to your S3 bucket) #icon=(link) #color=(#35a576)&lt;/a&gt; Then, follow the steps below&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-s3" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;


&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiObGag04VmyRJp6rdAdl2mwChDSSbvUb7qJb8iyoucrqZ8RoFU-XyN4sqcmPI_O9s9AJkFUrN-j3frKQcizPw3Qpd4l0YewT4iSqq4Rz1fSz5FL8zOh3plnFoWhzv0J_JkphFjxeQX56694l71Q2ZngZlVbk3ByDOf2DkKEV8dHWTI1emTVq5J-sLId4Hd/s1600/download-thumbnail-image.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Spring Cloud AWS S3 File Download Thumbnail Image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiObGag04VmyRJp6rdAdl2mwChDSSbvUb7qJb8iyoucrqZ8RoFU-XyN4sqcmPI_O9s9AJkFUrN-j3frKQcizPw3Qpd4l0YewT4iSqq4Rz1fSz5FL8zOh3plnFoWhzv0J_JkphFjxeQX56694l71Q2ZngZlVbk3ByDOf2DkKEV8dHWTI1emTVq5J-sLId4Hd/s1600/download-thumbnail-image.png"/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;strike&gt;toc&lt;/strike&gt;
&lt;br/&gt;

&lt;h2&gt;Dependencies&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;To get started with this tutorial, you'll need to add the following dependencies to your Spring Boot project's. This dependency provides the necessary components for interacting with AWS services, including S3.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Gradle&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "groovy"&gt;ext {
    springCloudAwsVersion = &amp;#39;3.0.0&amp;#39;
}

dependencies {
    // spring cloud aws BOM(Bill of materials)
    implementation platform(&amp;quot;io.awspring.cloud:spring-cloud-aws-dependencies:${springCloudAwsVersion}&amp;quot;)
    implementation &amp;#39;io.awspring.cloud:spring-cloud-aws-starter-s3&amp;#39;
    // AWS launched a high level file transfer utility, called Transfer Manager and a CRT based S3 client.
    // The starter automatically configures and registers a software.amazon.awssdk.transfer.s3.S3TransferManager bean if the following dependency is added to the project:
    implementation &amp;#39;software.amazon.awssdk:s3-transfer-manager&amp;#39;
    //Transfer Manager works the best with CRT S3 Client. To auto-configure CRT based S3AsyncClient add following dependency to your project:
    implementation &amp;#39;software.amazon.awssdk.crt:aws-crt&amp;#39;
}&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;h3&gt;Maven&lt;/h3&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;io.awspring.cloud&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-cloud-aws-starter-s3&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
	
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;software.amazon.awssdk&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;s3-transfer-manager&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
	
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;software.amazon.awssdk.crt&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;aws-crt&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;

&amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;io.awspring.cloud&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-cloud-aws-dependencies&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;{project-version}&amp;lt;/version&amp;gt;
            &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
            &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
       &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
&amp;lt;/dependencyManagement&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Configuration and Credentials&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Before initiating the object download process, let's configure our Spring Boot application to interact with AWS S3. Spring Cloud AWS offers auto-configuration for &lt;u&gt;S3Client, S3TransferManager, and S3Template&lt;/u&gt;, making setup a breeze.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Here's what you need to add to your &lt;code&gt;application.properties&lt;/code&gt; file:&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "properties"&gt; # s3 Configuration
 spring.cloud.aws.credentials.access-key=
 spring.cloud.aws.credentials.secret-key=
 # Configures endpoint used by S3Client, I&amp;#39;m woorking in the Asia Pacific (Mumbai) hence, I&amp;#39;ve configure ap-south1 region and endpoint
 spring.cloud.aws.s3.endpoint=https://s3.ap-south-1.amazonaws.com
 spring.cloud.aws.region.static=ap-south-1&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;IAM Permissions: Downloading S3 Objects&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Each AWS service requires specific permissions to perform operations. These permissions can be granted to IAM users through policies, AWS service roles, or other mechanisms.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;For this tutorial, we'll use an IAM user to download an object from S3. To enable this, we've attached the necessary policy to the IAM user. Alternatively, you can use an IAM role&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "json"&gt; {
    &amp;quot;Version&amp;quot;: &amp;quot;2012-10-17&amp;quot;,
    &amp;quot;Statement&amp;quot;: [
        {
            &amp;quot;Sid&amp;quot;: &amp;quot;DownloadFilePolicy&amp;quot;,
            &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
            &amp;quot;Action&amp;quot;: [
                &amp;quot;s3:GetObject&amp;quot;,
                &amp;quot;s3:ListBucketVersions&amp;quot;,
                &amp;quot;s3:ListBucket&amp;quot;
            ],
            &amp;quot;Resource&amp;quot;: [
                &amp;quot;arn:aws:s3:::*/*&amp;quot;,
                &amp;quot;arn:aws:s3:::learnjavaskills&amp;quot;
            ]
        }
    ]
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Downloading Files from AWS S3 with S3Client&lt;/h2&gt;
&lt;hr/&gt;

&lt;p&gt;Let's explore our first approach to downloading an object from Amazon S3. We'll utilize the &lt;a href="https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html" target="_blank" rel="nofollow"&gt;&lt;u&gt;S3Client&lt;/u&gt;&lt;/a&gt; interface, a dedicated service client for interacting with the S3 service.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The &lt;code&gt;S3Client&lt;/code&gt; interface is a fundamental component of the AWS SDK for Java. It provides a high-level API for interacting with Amazon Simple Storage Service (S3). This interface allows developers to perform various operations on S3 buckets and objects&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.GetObjectRequest;
 import java.nio.file.Path;

 public void downloadFileUsingS3Client(String bucketName, String key, String downloadDestinationPath) {
    try {
        GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();
        s3Client.getObject(getObjectRequest, Path.of(downloadDestinationPath));
    } catch (Exception exception) {
        exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;p&gt;The &lt;code&gt;getObject()&lt;/code&gt; method of &lt;code&gt;S3Client&lt;/code&gt; is the primary mechanism for downloading objects from an S3 bucket. It requires two parameters: a &lt;code&gt;GetObjectRequest&lt;/code&gt; object specifying the &lt;u&gt;bucket name and object key&lt;/u&gt;, and a local file path where the downloaded object will be saved.&lt;/p&gt;&lt;br/&gt;

&lt;h2&gt;Downloading Files from AWS S3 with S3TransferManager&lt;/h2&gt;
&lt;hr/&gt;

&lt;p&gt;&lt;code&gt;S3TransferManager&lt;/code&gt; is a powerful utility within the AWS SDK for Java that simplifies the process of transferring files to and from Amazon S3.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;It offers enhanced performance and reliability by leveraging Amazon S3's multipart upload and byte-range fetch capabilities.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.services.s3.model.GetObjectRequest;
 import software.amazon.awssdk.transfer.s3.S3TransferManager;
 import software.amazon.awssdk.transfer.s3.model.DownloadFileRequest;
 import software.amazon.awssdk.transfer.s3.model.FileDownload;
 import software.amazon.awssdk.transfer.s3.model.CompletedFileDownload;
 import java.nio.file.Path;

 public void downloadFileUsingS3TransferManager(String bucketName, String key, String downloadDestinationPath) {
    try {
        GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();

        DownloadFileRequest downloadFileRequest = DownloadFileRequest.builder()
                .destination(Path.of(downloadDestinationPath))
                .getObjectRequest(getObjectRequest)
                .build();
        FileDownload fileDownload = s3TransferManager.downloadFile(downloadFileRequest);
        CompletedFileDownload completedFileDownload = fileDownload.completionFuture()
                .join();
        String contentType = completedFileDownload.response()
                .contentType();
        System.out.println("Download completed, content type is : " + contentType);
    } catch (Exception exception) {
        exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;p&gt;The &lt;code&gt;downloadFile()&lt;/code&gt; method of &lt;code&gt;S3TransferManager&lt;/code&gt; facilitates downloading S3 objects. It requires a &lt;code&gt;DownloadFileRequest&lt;/code&gt; object as an argument.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This request specifies the object's details, including the local destination path and an &lt;code&gt;GetObjectRequest&lt;/code&gt; instance containing the &lt;u&gt;bucket name and key&lt;/u&gt;, as discussed in our previous example.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Understanding completionFuture()&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;completionFuture&lt;/code&gt; method in the FileDownload interface of the AWS SDK for Java provides a way to asynchronously track the progress and completion of an S3 file download operation.&lt;/p&gt;&lt;br/&gt;
&lt;p&gt;It returns a &lt;code&gt;CompletableFuture&amp;#x3C;Void&amp;#x3E;&lt;/code&gt; object, which represents the future result of the download operation. Key points about completionFuture:&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;bull; Asynchronous Execution&lt;/p&gt;
&lt;p&gt;&amp;bull; Progress Tracking&lt;/p&gt;
&lt;p&gt;&amp;bull; Error Handling&lt;/p&gt;
&lt;p&gt;&amp;bull; Completion Notification&lt;/p&gt;&lt;br/&gt;

&lt;h2&gt;Downloading Directories from AWS S3 with S3TransferManager&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Similarly, we can efficiently download entire directories or buckets from Amazon S3 using &lt;code&gt;S3TransferManager&lt;/code&gt;. To accomplish this, we employ the &lt;code&gt;downloadDirectory()&lt;/code&gt; method instead of &lt;code&gt;downloadFile()&lt;/code&gt; method.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.transfer.s3.S3TransferManager;
 import software.amazon.awssdk.transfer.s3.model.DownloadDirectoryRequest;
 import software.amazon.awssdk.transfer.s3.model.DirectoryDownload;
 import software.amazon.awssdk.transfer.s3.model.CompletedDirectoryDownload;
 import java.nio.file.Path;

 public void downloadDirectoryUsingS3TransferManager(String bucketName, String downloadDestinationPath) {
    try {
        DownloadDirectoryRequest downloadDirectoryRequest = DownloadDirectoryRequest.builder()
                .bucket(bucketName)
                .destination(Path.of(downloadDestinationPath))
                .build();
        DirectoryDownload directoryDownload = s3TransferManager.downloadDirectory(downloadDirectoryRequest);
        CompletedDirectoryDownload completedDirectoryDownload = directoryDownload.completionFuture()
                .join();
        completedDirectoryDownload.failedTransfers()
                .forEach(failedFileDownload -&amp;gt; System.out.println(&amp;quot;fail to download : &amp;quot; + failedFileDownload.toString()));
    } catch (Exception exception) {
        exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Downloading Files with S3Template&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;The &lt;code&gt;S3Template&lt;/code&gt; class in the Spring Cloud AWS library provides a high-level abstraction for interacting with Amazon S3. It simplifies common S3 operations, making it easier to integrate S3 functionality into your Spring Boot applications.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The S3Template provides a convenient &lt;code&gt;download()&lt;/code&gt; method for retrieving objects from Amazon S3. This method requires two arguments: &lt;u&gt;the bucket name and the object key&lt;/u&gt;, which uniquely identify the desired object within the S3 storage.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import io.awspring.cloud.s3.S3Resource;
 import io.awspring.cloud.s3.S3Template;
 import java.io.InputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;

 public void downloadFileUsingS3Template(String bucketName, String key, String downloadDestinationPath) {
    try {
        S3Resource s3Resource = s3Template.download(bucketName, key);
        InputStream inputStream = s3Resource.getInputStream();
        Files.copy(inputStream, Path.of(downloadDestinationPath), StandardCopyOption.REPLACE_EXISTING);
    } catch (Exception exception) {
        exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Conclussion&lt;/h2&gt;
&lt;hr/&gt;

&lt;p&gt;For Spring Boot applications requiring single file downloads, &lt;code&gt;S3Template&lt;/code&gt; offers an efficient and convenient approach.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;In legacy Java applications without Spring Cloud AWS integration, consider using &lt;code&gt;S3Client&lt;/code&gt; for object downloads.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&lt;code&gt;S3TransferManager&lt;/code&gt; provides the most efficient and feature-rich option for object downloads, offering benefits like progress tracking, error handling, and asynchronous communication, making it well-suited for multithreaded environments.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Learn how to efficiently &lt;a href="https://www.learnjavaskills.in/2024/10/read-s3-file-into-java-input-stream.html"&gt;(getButton) #text=(read files directly into a Java input stream) #icon=(link) #color=(#35a576)&lt;/a&gt; without the need for downloading&lt;/p&gt;&lt;br/&gt;


&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-s3" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;</content><link href="https://www.learnjavaskills.in/feeds/9155813656576735610/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/10/spring-cloud-aws-s3-file-download.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/9155813656576735610" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/9155813656576735610" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/10/spring-cloud-aws-s3-file-download.html" rel="alternate" title="Spring Cloud AWS S3 File Download Tutorial: Step-by-Step Guide" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiObGag04VmyRJp6rdAdl2mwChDSSbvUb7qJb8iyoucrqZ8RoFU-XyN4sqcmPI_O9s9AJkFUrN-j3frKQcizPw3Qpd4l0YewT4iSqq4Rz1fSz5FL8zOh3plnFoWhzv0J_JkphFjxeQX56694l71Q2ZngZlVbk3ByDOf2DkKEV8dHWTI1emTVq5J-sLId4Hd/s72-c/download-thumbnail-image.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-5595989275608218053</id><published>2024-10-12T20:11:00.000+05:30</published><updated>2024-10-12T20:11:12.564+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">Spring Cloud AWS S3 File Upload Tutorial: Step-by-Step Guide</title><content type="html">
&lt;p&gt;In today's digital age, storing and managing large amounts of data is crucial for many applications. Amazon Simple Storage Service (S3) offers a reliable and scalable solution for object storage in the cloud.&lt;/p&gt;&lt;br/&gt;
  
&lt;p&gt;Spring Cloud AWS provides a convenient way to integrate S3 functionality into Spring Boot applications.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This article will guide you through the process of uploading files to Amazon S3 using Spring Cloud AWS, covering essential steps and configurations. By the end, you'll have a solid understanding of how to leverage S3 storage for your Spring Boot applications.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;To get started with uploading files to Amazon S3, make sure you have a bucket ready. Refer to my previous blog posts for instructions on &lt;a href="https://www.learnjavaskills.in/2024/09/spring-cloud-aws-s3-bucket-operations.html"&gt;(getButton) #text=(creating, deleting, and managing buckets) #icon=(link) #color=(#35a576)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-s3" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJGSM8pl85OZGH28BQtC9DrNpoKQEBjPUdPX_l6f01wWqh3YODRDQ9JjYFBgAWGIWHf-v32ynk18SOFKrDW-ZETkBBk34hDOnR9b1w0mXcYWU_bd1FTureTqXv5qF2c02hm_NWLPIM1I0wsWp1Lm9bREMSkkoLwArka0_VO6VOD3GIIM_IslN8IrSTXl17/s1600/Thumbnail-Image.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Spring Cloud AWS S3 File Upload Thumbnail Image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJGSM8pl85OZGH28BQtC9DrNpoKQEBjPUdPX_l6f01wWqh3YODRDQ9JjYFBgAWGIWHf-v32ynk18SOFKrDW-ZETkBBk34hDOnR9b1w0mXcYWU_bd1FTureTqXv5qF2c02hm_NWLPIM1I0wsWp1Lm9bREMSkkoLwArka0_VO6VOD3GIIM_IslN8IrSTXl17/s1600/Thumbnail-Image.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;strike&gt;toc&lt;/strike&gt;
&lt;br/&gt;

&lt;h2&gt;Dependencies&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;To get started with this tutorial, you'll need to add the following dependencies to your Spring Boot project's. This dependency provides the necessary components for interacting with AWS services, including S3.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Gradle&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "groovy"&gt;ext {
    springCloudAwsVersion = &amp;#39;3.0.0&amp;#39;
}

dependencies {
    // spring cloud aws BOM(Bill of materials)
    implementation platform(&amp;quot;io.awspring.cloud:spring-cloud-aws-dependencies:${springCloudAwsVersion}&amp;quot;)
    implementation &amp;#39;io.awspring.cloud:spring-cloud-aws-starter-s3&amp;#39;
    // AWS launched a high level file transfer utility, called Transfer Manager and a CRT based S3 client.
    // The starter automatically configures and registers a software.amazon.awssdk.transfer.s3.S3TransferManager bean if the following dependency is added to the project:
    implementation &amp;#39;software.amazon.awssdk:s3-transfer-manager&amp;#39;
    //Transfer Manager works the best with CRT S3 Client. To auto-configure CRT based S3AsyncClient add following dependency to your project:
    implementation &amp;#39;software.amazon.awssdk.crt:aws-crt&amp;#39;
}&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;h3&gt;Maven&lt;/h3&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;io.awspring.cloud&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-cloud-aws-starter-s3&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
	
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;software.amazon.awssdk&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;s3-transfer-manager&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
	
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;software.amazon.awssdk.crt&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;aws-crt&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;

&amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;io.awspring.cloud&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-cloud-aws-dependencies&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;{project-version}&amp;lt;/version&amp;gt;
            &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
            &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
       &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
&amp;lt;/dependencyManagement&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Configuration and Credentials&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Before we get started with uploading files, let's configure our Spring Boot application to interact with AWS S3. Spring Cloud AWS offers auto-configuration for &lt;u&gt;S3Client, S3TransferManager, and S3Template&lt;/u&gt;, making setup a breeze.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Here's what you need to add to your &lt;code&gt;application.properties&lt;/code&gt; file:&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "properties"&gt; # s3 Configuration
 spring.cloud.aws.credentials.access-key=
 spring.cloud.aws.credentials.secret-key=
 # Configures endpoint used by S3Client, I&amp;#39;m woorking in the Asia Pacific (Mumbai) hence, I&amp;#39;ve configure ap-south1 region and endpoint
 spring.cloud.aws.s3.endpoint=https://s3.ap-south-1.amazonaws.com
 spring.cloud.aws.region.static=ap-south-1&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;IAM Permissions for Bucket Management&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;In this in-depth tutorial, we'll explore various features of AWS S3, including tagging, metadata, and file uploading. We'll delve into multiple approaches for uploading files.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;To seamlessly upload files with tags and metadata, your Amazon Simple Storage Service (S3) bucket will require the following IAM permissions.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "json"&gt; {
    &amp;quot;Version&amp;quot;: &amp;quot;2012-10-17&amp;quot;,
    &amp;quot;Statement&amp;quot;: [
        {
            &amp;quot;Sid&amp;quot;: &amp;quot;uploadFile&amp;quot;,
            &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
            &amp;quot;Action&amp;quot;: [
                &amp;quot;s3:PutObject&amp;quot;,
                &amp;quot;s3:PutObjectTagging&amp;quot;,
                &amp;quot;s3:GetObjectTagging&amp;quot;
            ],
            &amp;quot;Resource&amp;quot;: &amp;quot;arn:aws:s3:::*/*&amp;quot;
        }
    ]
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;AWS S3 File Upload with S3Client&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;One of the most straightforward ways to upload a file to Amazon Simple Storage Service (S3) is by using the &lt;code&gt;S3Client&lt;/code&gt; interface. &lt;a href="https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html" target="_blank" rel="nofollow"&gt;&lt;u&gt;S3Client&lt;/u&gt;&lt;/a&gt; is a service client designed for interacting with Amazon S3.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
 import software.amazon.awssdk.core.sync.RequestBody;
 import java.nio.file.Paths;

 public void uploadFileUsingS3Client(String bucketName, String key, String filePath) {
    try {
        PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();
        s3Client.putObject(putObjectRequest, RequestBody.fromFile(Paths.get(filePath)));
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;p&gt;The &lt;code&gt;putObject()&lt;/code&gt; method of S3Client is your gateway to uploading files to your Amazon S3 bucket. It takes two arguments: a &lt;code&gt;PutObjectRequest&lt;/code&gt; object and a &lt;code&gt;RequestBody&lt;/code&gt;, which specifies the exact file you want to upload.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;b&gt;PutObjectRequest&lt;/b&gt; is a class (located in the &lt;code&gt;com.amazonaws.services.s3.model&lt;/code&gt; package) that allows you to configure the upload process.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022; To create a valid PutObjectRequest, specifying the target &lt;b&gt;bucket&lt;/b&gt; name and the &lt;b&gt;key&lt;/b&gt; (unique identifier) for the file is essential.&lt;/p&gt;

&lt;br/&gt;

&lt;h3&gt;Running Unit Tests for File Uploading&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 void uploadFileUsingS3Client()
 {
    uploadObjects.uploadFileUsingS3Client(bucketName, &amp;quot;robot.gif&amp;quot;, filePath);
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;File Upload Successful to Amazon S3&lt;/h3&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEia_znIS2ykr7ThbsTiE8mnBxlRnLdmeP1EUyoNUIl9y9bh-82vU7gLk3RSwNo56bHB7WVxqUcpYJeAuUOF3xJK_VDJAm04YqzFMTd7Nj5FqkB9q3srUDmBgs5jFa6HzBpmHmNz5cmjl92oYnphdL-DTVsFuE7l01n2VR7okHlYtQh49Bdr1GEsOJ-mnltd/s1600/upload-using-s3-client.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="amazon s3 bucket console" border="0" data-original-height="416" data-original-width="952" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEia_znIS2ykr7ThbsTiE8mnBxlRnLdmeP1EUyoNUIl9y9bh-82vU7gLk3RSwNo56bHB7WVxqUcpYJeAuUOF3xJK_VDJAm04YqzFMTd7Nj5FqkB9q3srUDmBgs5jFa6HzBpmHmNz5cmjl92oYnphdL-DTVsFuE7l01n2VR7okHlYtQh49Bdr1GEsOJ-mnltd/s1600/upload-using-s3-client.png"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br/&gt;


&lt;h2&gt;Efficient File Uploads and Tagging with S3Client&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;&lt;b&gt;Tagging&lt;/b&gt; in Amazon S3 is a powerful feature that allows you to attach metadata to your objects. These metadata tags are key-value pairs that provide additional information about your objects, making them easier to categorize, search, and manage.&lt;/p&gt;&lt;br&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
 import software.amazon.awssdk.services.s3.model.Tag;
 import software.amazon.awssdk.services.s3.model.Tagging;
 import software.amazon.awssdk.core.sync.RequestBody;
 import java.nio.file.Paths;
 import java.util.List;

 public void uploadFileWithTag(String bucketName, String key, String filePath) {
    try {
        Tag tag1 = Tag.builder().
                key(&amp;quot;tag 1&amp;quot;)
                .value(&amp;quot;tag 1 value&amp;quot;)
                .build();
        Tag tag2 = Tag.builder()
                .key(&amp;quot;tag 2&amp;quot;)
                .value(&amp;quot;tag 2 value&amp;quot;)
                .build();

        List&amp;lt;Tag&amp;gt; tagList = List.of(tag1, tag2);
        Tagging tagging = Tagging.builder()
                .tagSet(tagList)
                .build();

        PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .tagging(tagging)
                .build();
        s3Client.putObject(putObjectRequest, RequestBody.fromFile(Paths.get(filePath)));
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;p&gt;To tag an object in Amazon S3, simply use the &lt;code&gt;Tagging&lt;/code&gt; class to add your desired key-value pairs while uploading the file. The Tagging class has a &lt;code&gt;tagSet()&lt;/code&gt; method that accepts a list of Tag objects.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;To tag an object while uploading it to Amazon S3, use the &lt;code&gt;tagging()&lt;/code&gt; method of the &lt;b&gt;PutObjectRequest&lt;/b&gt; class to provide the desired tagging information.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Testing File Uploads with Tags&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 void uploadFileWithTag()
 {
    uploadObjects.uploadFileWithTag(bucketName, &amp;quot;robot-with-tag.gif&amp;quot;, filePath);
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;Verifying Tagged File Uploads&lt;/h3&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgQV1KC5xvANbSjtGFnWN3cYfOlFyu0BTit8RBTGoyUT0AwePR7wc57h7z-TrzOOGuaIJ00W749M0p8XTIRGOav77GULERFt5uUE9DX2u5msEif-0dCnC64V-b-ApJB9jJlnob6MaMOu9asjB9hpicVVi29KZQb2W4F3UheH9k7Gxw-e96eIjGI1zkLvdF/s1600/put-object-with-tag.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Amazon S3 bucket console with tags information" border="0" data-original-height="704" data-original-width="950" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgQV1KC5xvANbSjtGFnWN3cYfOlFyu0BTit8RBTGoyUT0AwePR7wc57h7z-TrzOOGuaIJ00W749M0p8XTIRGOav77GULERFt5uUE9DX2u5msEif-0dCnC64V-b-ApJB9jJlnob6MaMOu9asjB9hpicVVi29KZQb2W4F3UheH9k7Gxw-e96eIjGI1zkLvdF/s1600/put-object-with-tag.png"/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br/&gt;

&lt;h2&gt;Efficiently Updating Tag Information for S3 Files&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;You may need to update or modify the tag information associated with an Amazon S3 object. To do this, you must first retrieve the existing tags from the S3 bucket.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;You can then update or create new tags as needed. Once you've configured the desired tag information, you can apply these changes to the S3 object by using the &lt;code&gt;PutObjectTaggingRequest&lt;/code&gt; class.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
 import software.amazon.awssdk.services.s3.model.GetObjectTaggingRequest;
 import software.amazon.awssdk.services.s3.model.GetObjectTaggingResponse;
 import software.amazon.awssdk.services.s3.model.PutObjectTaggingRequest;
 import software.amazon.awssdk.services.s3.model.Tag;
 import software.amazon.awssdk.services.s3.model.Tagging;
 import java.util.List;

 public void updateObjectTag(String bucketName, String key) {
    try {
        GetObjectTaggingRequest getObjectTaggingRequest = GetObjectTaggingRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();
        GetObjectTaggingResponse objectTagging = s3Client.getObjectTagging(getObjectTaggingRequest);

        // print existing tags
        objectTagging.tagSet()
                .stream()
                .forEach(tag -&amp;gt; System.out.println(&amp;quot;tag key : &amp;quot; + tag.key() + &amp;quot; tag value : &amp;quot; + tag.value()));

        // new tags add
        Tag tag3 = Tag.builder()
                    .key(&amp;quot;tag 3&amp;quot;)
                    .value(&amp;quot;tag 3 value&amp;quot;)
                    .build();
        Tag tag4 = Tag.builder()
                    .key(&amp;quot;tag 4&amp;quot;)
                    .value(&amp;quot;tag 4 value&amp;quot;)
                    .build();

        List&amp;lt;Tag&amp;gt; tagList = List.of(tag3, tag4);
        Tagging updatedTags = Tagging.builder()
                .tagSet(tagList)
                .build();

        PutObjectTaggingRequest putObjectTaggingRequest = PutObjectTaggingRequest.builder()
                .bucket(bucketName)
                .key(key)
                .tagging(updatedTags)
                .build();

        // update tags
        s3Client.putObjectTagging(putObjectTaggingRequest);
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;


&lt;h3&gt;Testing Tag Updates in Amazon S3&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 void updateObjectTag()
 {
    uploadObjects.updateObjectTag(bucketName, &amp;quot;robot-with-tag.gif&amp;quot;);
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;Tag Update Successful&lt;/h3&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfpRJcU5-pDxhaVvNJfLVQLZDd0oAuRT108cGKt6NKHdVFPMd2dneD1zup9lI-VxC0WsX-BC8Z_YnwCIgWw0ck1anfeHHYaXe5bhyphenhyphennyhoRy2OMTsyb3ur-91AWyh_8wnUBm0eMRijn69bczMvzQ-kXX2g4CBblaCPq2A4LU0SDJxFqXIN2ZTTUr7EVClz1/s1600/update-tag.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Amazon S3 bucket console with tag information" border="0" data-original-height="680" data-original-width="940" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfpRJcU5-pDxhaVvNJfLVQLZDd0oAuRT108cGKt6NKHdVFPMd2dneD1zup9lI-VxC0WsX-BC8Z_YnwCIgWw0ck1anfeHHYaXe5bhyphenhyphennyhoRy2OMTsyb3ur-91AWyh_8wnUBm0eMRijn69bczMvzQ-kXX2g4CBblaCPq2A4LU0SDJxFqXIN2ZTTUr7EVClz1/s1600/update-tag.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br/&gt;

&lt;h2&gt;AWS S3 File Upload with S3Client: Adding Metadata to Uploading Files&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Metadata is a set of data that describes an object stored in Amazon S3. It provides additional information about the object, such as its creation date, size, content type, and custom user-defined attributes.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This metadata can be used to organize, search, and manage your objects more effectively.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Key types of metadata in S3:&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;b&gt;System-defined metadata&lt;/b&gt;: This metadata is automatically created and managed by S3 and includes information like object size, creation date, and storage class.&lt;p&gt;&lt;br/&gt;
  
&lt;p&gt;&amp;#x2022; &lt;b&gt;User-defined metadata&lt;/b&gt;: This metadata is added by the user and can contain any key-value pairs. It's a flexible way to store custom information about your objects.&lt;p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
 import software.amazon.awssdk.core.sync.RequestBody;
 import java.nio.file.Paths;
 import java.util.Map;

 public void uploadFileWithMetaData(String bucketName, String key, String filePath) {
    try {
        Map&amp;lt;String, String&amp;gt; metadata = new HashMap&amp;lt;&amp;gt;();
        metadata.put(&amp;quot;author&amp;quot;, &amp;quot;learnjavaskills.in&amp;quot;);
        metadata.put(&amp;quot;file-type&amp;quot;, &amp;quot;txt&amp;quot;);
        metadata.put(&amp;quot;version&amp;quot;, &amp;quot;1.0&amp;quot;);

        PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .metadata(metadata)
                .build();
        s3Client.putObject(putObjectRequest, RequestBody.fromFile(Paths.get(filePath)));
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;Testing File Uploads with Metadata in Amazon S3&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 void uploadFileWithMetaData()
 {
    uploadObjects.uploadFileWithMetaData(bucketName, &amp;quot;robot-with-meta-data.gif&amp;quot;, filePath);
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;


&lt;h3&gt;File Upload Successful with Metadata&lt;/h3&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj15EmVsaiK-FAMa99Z3AXs2nud9-f9PllAsgHxvToVl3JQSYD8kNvGX13984X2k78Pv9D014rk6lVxG9VJr1Je1eHwN8YKVrpoS0awCSxIooUytvb4TkDSh1ucsNookvGcEu_9pStaO70pNAHP2p3On0vKdJozUVu8HazJZZ6XJegBvnclDqWE9VeIMGtb/s1600/put-object-with-meta-data.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Amazon s3 bucket console with metadata information" border="0" data-original-height="812" data-original-width="948" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj15EmVsaiK-FAMa99Z3AXs2nud9-f9PllAsgHxvToVl3JQSYD8kNvGX13984X2k78Pv9D014rk6lVxG9VJr1Je1eHwN8YKVrpoS0awCSxIooUytvb4TkDSh1ucsNookvGcEu_9pStaO70pNAHP2p3On0vKdJozUVu8HazJZZ6XJegBvnclDqWE9VeIMGtb/s1600/put-object-with-meta-data.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br/&gt;


&lt;h2&gt;AWS S3 File Upload with S3TransferManager&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;The &lt;code&gt;S3TransferManager&lt;/code&gt; class in the AWS SDK for Java provides a high-level API for managing asynchronous data transfers to and from Amazon S3.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;It handles the complexities of multi-part uploads, retries, and error handling, making it a convenient choice for large file transfers or bulk data operations.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.transfer.s3.S3TransferManager;
 import software.amazon.awssdk.transfer.s3.model.UploadFileRequest;
 import software.amazon.awssdk.transfer.s3.model.FileUpload;
 import software.amazon.awssdk.transfer.s3.model.CompletedFileUpload;
 import java.nio.file.Paths;
 import java.util.OptionalLong;

 public void uploadFileWithTransferManager(String bucketName, String key, String filePath) {
    try
    {
        UploadFileRequest uploadFileRequest = UploadFileRequest.builder()
                .putObjectRequest(builder -&amp;gt; builder.bucket(bucketName)
                        .key(key))
                .source(Paths.get(filePath))
                .build();
        FileUpload fileUpload = s3transferManager.uploadFile(uploadFileRequest);
        // check progress of file upload
        while (true)
        {
            OptionalLong optionalLong = fileUpload.progress()
                    .snapshot()
                    .remainingBytes();
            if (optionalLong.isPresent())
            {
                System.out.println(&amp;quot;remaining byte transfer : &amp;quot; + optionalLong.getAsLong());
                if (optionalLong.getAsLong() == 0)
                    break;
            }
        }

        CompletedFileUpload completedFileUpload = fileUpload.completionFuture().join();
        boolean successful = completedFileUpload.response().sdkHttpResponse().isSuccessful();
        System.out.println(&amp;quot;is Successful : &amp;quot; + successful);
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;AWS S3 File Upload with S3Template&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;The &lt;code&gt;S3Template&lt;/code&gt; class in the Spring Cloud AWS library provides a high-level abstraction for interacting with Amazon S3. It simplifies common S3 operations, making it easier to integrate S3 functionality into your Spring Boot applications.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;A straightforward way to upload a file to Amazon Simple Storage Service (S3) is by using the &lt;code&gt;upload()&lt;/code&gt; method provided by &lt;b&gt;S3Template&lt;/b&gt;.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The &lt;code&gt;upload()&lt;/code&gt; method requires three essential arguments: &lt;u&gt;the bucket name, the object key, and the file's input stream&lt;/u&gt;.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import io.awspring.cloud.s3.S3Template;
 import io.awspring.cloud.s3.S3Resource;
 import java.io.FileInputStream;
 import java.io.InputStream;
 import java.net.URL;

 public void uploadFileUsingS3Template(String bucketName, String key, String filePath) {
    try {
        InputStream inputStream = new FileInputStream(filePath);
        S3Resource s3Resource = s3Template.upload(bucketName, key, inputStream);
        URL url = s3Resource.getURL();
        System.out.println(&amp;quot;File uploaded successfully at &amp;quot; + url.toString());
    } catch (S3Exception | IOException exception) {
        exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;


&lt;br/&gt;

&lt;h2&gt;AWS S3 File Upload with S3Template: Adding Metadata to Uploaded Files&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;S3Template also allows you to add custom metadata to an Amazon S3 object. An overloaded version of the &lt;code&gt;upload()&lt;/code&gt; method accepts &lt;u&gt;metadata&lt;/u&gt; as an argument, in addition to the &lt;u&gt;bucket name, object key, and input stream of the file&lt;/u&gt;.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import io.awspring.cloud.s3.S3Template;
 import io.awspring.cloud.s3.S3Resource;
 import java.io.FileInputStream;
 import java.io.InputStream;
 import io.awspring.cloud.s3.ObjectMetadata;
 import java.net.URL;

 public void uploadFileUsingS3TemplateWithMetadata(String bucketName, String key, String filePath) {
    try {
        InputStream inputStream = new FileInputStream(filePath);
        ObjectMetadata objectMetadata = ObjectMetadata.builder()
                .metadata(&amp;quot;author&amp;quot;, &amp;quot;learnjavaskills.in&amp;quot;)
                .metadata(&amp;quot;version&amp;quot;, &amp;quot;1.0&amp;quot;)
                .contentType(&amp;quot;text/plain&amp;quot;)
                .build();
        S3Resource s3Resource = s3Template.upload(bucketName, key, inputStream, objectMetadata);
        URL url = s3Resource.getURL();
        System.out.println(&amp;quot;File uploaded successfully at &amp;quot; + url.toString());
    }catch (S3Exception | IOException exception) {
        exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;Testing File Uploads with Metadata&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 void uploadFileUsingS3TemplateWithMetadata()
 {
    uploadObjects.uploadFileUsingS3TemplateWithMetadata(bucketName, &amp;quot;robot-s3-template-metadata.gif&amp;quot;, filePath);
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;Verifying Amazon S3 Objects with Metadata&lt;/h3&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc1LJ4fWUx1GQqEFam7EoB-VxNQ2g3DicJBUTuVNRA7r8WZkuxihLIcC6yJg6sv6Wnwwv3HrpIom0Obk0aTcr4x2hra_qVIyXZRxgcf0C2pbMKbMpw_gcSi9wErOvUhYQQpG7EaFBvtrKTRhAtJxmzYDcQLjkDwkA3DFMJLcimX2KBCTGNygfUgkrOv138/s1600/s3-template-upload-metadata.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Amazon S3 BUcket Console with MetaData information" border="0" data-original-height="832" data-original-width="1176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc1LJ4fWUx1GQqEFam7EoB-VxNQ2g3DicJBUTuVNRA7r8WZkuxihLIcC6yJg6sv6Wnwwv3HrpIom0Obk0aTcr4x2hra_qVIyXZRxgcf0C2pbMKbMpw_gcSi9wErOvUhYQQpG7EaFBvtrKTRhAtJxmzYDcQLjkDwkA3DFMJLcimX2KBCTGNygfUgkrOv138/s1600/s3-template-upload-metadata.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;h2&gt;Conclussion&lt;/h2&gt;
&lt;hr&gt;
  
&lt;p&gt;For Spring Boot projects, &lt;code&gt;S3Template&lt;/code&gt; simplifies file uploads with its convenient &lt;code&gt;upload()&lt;/code&gt; method.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&lt;code&gt;S3TransferManager&lt;/code&gt; offers significant advantages over &lt;code&gt;S3Client&lt;/code&gt;, including multi-part uploads, asynchronous transfers, robust error handling, and progress tracking.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;While &lt;code&gt;S3Client&lt;/code&gt; is suitable for small file uploads, &lt;code&gt;S3TransferManager&lt;/code&gt; excels in handling larger files and complex transfer scenarios.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Now that you've successfully uploaded your files to Amazon S3, let's explore how to &lt;a href="https://www.learnjavaskills.in/2024/10/spring-cloud-aws-s3-file-download.html"&gt;(getButton) #text=(download files from S3 bucket) #icon=(link) #color=(#35a576)&lt;/a&gt; when needed.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-s3" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;






</content><link href="https://www.learnjavaskills.in/feeds/5595989275608218053/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/10/spring-cloud-aws-s3-file-upload.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/5595989275608218053" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/5595989275608218053" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/10/spring-cloud-aws-s3-file-upload.html" rel="alternate" title="Spring Cloud AWS S3 File Upload Tutorial: Step-by-Step Guide" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJGSM8pl85OZGH28BQtC9DrNpoKQEBjPUdPX_l6f01wWqh3YODRDQ9JjYFBgAWGIWHf-v32ynk18SOFKrDW-ZETkBBk34hDOnR9b1w0mXcYWU_bd1FTureTqXv5qF2c02hm_NWLPIM1I0wsWp1Lm9bREMSkkoLwArka0_VO6VOD3GIIM_IslN8IrSTXl17/s72-c/Thumbnail-Image.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-2784209087088086656</id><published>2024-10-12T17:12:00.000+05:30</published><updated>2024-10-12T17:12:39.638+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">Spring Cloud AWS S3 Bucket Operations (Create, List, Delete)</title><content type="html">&lt;p&gt;In this blog post, we'll delve into the world of Spring Boot and AWS S3 bucket management. We'll explore how to seamlessly integrate AWS S3 into your Spring Boot applications using Spring Cloud AWS, a powerful framework that simplifies the process of interacting with AWS services.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;By the end of this tutorial, you'll have a solid understanding of how to &lt;b&gt;list&lt;/b&gt;, &lt;b&gt;create&lt;/b&gt;, and &lt;b&gt;delete&lt;/b&gt; S3 buckets using Spring Cloud AWS, enabling you to efficiently manage your cloud storage needs.&lt;/p&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-s3" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO_KblFRLuMG6eAxL5wbDhcUBV3SKM3XWog7vARqUTXxDeNsbh3yTwfv9oyiKbultTQyDXiv0fRfSOZ-Gb4O2vZqpN68tB9_hHYQaK1BaxD-MeWSZPT9V8pKbDjSaz7s3Rat6Sg9v-66M7yxkA3dAkoGZpwzVWHFMBxkadTWq3V5oniCa6dOu-vOF2icPe/s1600/Spring%20cloud%20Aws.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Bucket Operations (Create, List, Delete)" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO_KblFRLuMG6eAxL5wbDhcUBV3SKM3XWog7vARqUTXxDeNsbh3yTwfv9oyiKbultTQyDXiv0fRfSOZ-Gb4O2vZqpN68tB9_hHYQaK1BaxD-MeWSZPT9V8pKbDjSaz7s3Rat6Sg9v-66M7yxkA3dAkoGZpwzVWHFMBxkadTWq3V5oniCa6dOu-vOF2icPe/s1600/Spring%20cloud%20Aws.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;strike&gt;toc&lt;/strike&gt;
&lt;br/&gt;

&lt;h2&gt;Dependencies&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;To get started with this tutorial, you'll need to add the following dependencies to your Spring Boot project's. This dependency provides the necessary components for interacting with AWS services, including S3.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Gradle&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "groovy"&gt;ext {
    springCloudAwsVersion = &amp;#39;3.0.0&amp;#39;
}

dependencies {
    // spring cloud aws BOM(Bill of materials)
    implementation platform(&amp;quot;io.awspring.cloud:spring-cloud-aws-dependencies:${springCloudAwsVersion}&amp;quot;)
    implementation &amp;#39;io.awspring.cloud:spring-cloud-aws-starter-s3&amp;#39;
    // AWS launched a high level file transfer utility, called Transfer Manager and a CRT based S3 client.
    // The starter automatically configures and registers a software.amazon.awssdk.transfer.s3.S3TransferManager bean if the following dependency is added to the project:
    implementation &amp;#39;software.amazon.awssdk:s3-transfer-manager&amp;#39;
    //Transfer Manager works the best with CRT S3 Client. To auto-configure CRT based S3AsyncClient add following dependency to your project:
    implementation &amp;#39;software.amazon.awssdk.crt:aws-crt&amp;#39;
}&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;h3&gt;Maven&lt;/h3&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;io.awspring.cloud&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-cloud-aws-starter-s3&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
	
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;software.amazon.awssdk&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;s3-transfer-manager&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
	
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;software.amazon.awssdk.crt&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;aws-crt&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;

&amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;io.awspring.cloud&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-cloud-aws-dependencies&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;{project-version}&amp;lt;/version&amp;gt;
            &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
            &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
       &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
&amp;lt;/dependencyManagement&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Configuration and Credentials&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Before diving into bucket operations, let's configure our Spring Boot application to interact with AWS S3.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Spring Cloud AWS offers auto-configuration for &lt;code&gt;S3Client&lt;/code&gt;, &lt;code&gt;S3TransferManager&lt;/code&gt;, and &lt;code&gt;S3Template&lt;/code&gt;, making setup a breeze. Here's what you need to add to your &lt;b&gt;&lt;u&gt;application.properties&lt;/u&gt;&lt;/b&gt; file:&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "properties"&gt; # s3 Configuration
 spring.cloud.aws.credentials.access-key=
 spring.cloud.aws.credentials.secret-key=
 # Configures endpoint used by S3Client, I&amp;#39;m woorking in the Asia Pacific (Mumbai) hence, I&amp;#39;ve configure ap-south1 region and endpoint
 spring.cloud.aws.s3.endpoint=https://s3.ap-south-1.amazonaws.com
 spring.cloud.aws.region.static=ap-south-1&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;IAM Permissions for Bucket Management&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;You must apply this policy to your IAM user or role to enable listing, creation, and deletion of buckets.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "json"&gt; {
    &amp;quot;Version&amp;quot;: &amp;quot;2012-10-17&amp;quot;,
    &amp;quot;Statement&amp;quot;: [
        {
            &amp;quot;Sid&amp;quot;: &amp;quot;ListCreateDeleteBucket&amp;quot;,
            &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
            &amp;quot;Action&amp;quot;: [
                &amp;quot;s3:DeleteBucketWebsite&amp;quot;,
                &amp;quot;s3:CreateBucket&amp;quot;,
                &amp;quot;s3:ListBucket&amp;quot;,
                &amp;quot;s3:DeleteBucket&amp;quot;,
                &amp;quot;s3:GetObject&amp;quot;,
                &amp;quot;s3:DeleteObjectVersion&amp;quot;,
                &amp;quot;s3:DeleteObject&amp;quot;
            ],
            &amp;quot;Resource&amp;quot;: &amp;quot;arn:aws:s3:::*&amp;quot;
        }
    ]
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Creating an S3 Bucket with S3Client&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;&lt;a href="https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html" target="_blank" rel="nofollow"&gt;&lt;u&gt;S3Client&lt;/u&gt;&lt;/a&gt; is a Java interface that interacts with Amazon Simple Storage Service (S3). An S3 bucket is like a virtual folder where you can store any type of file. Buckets have unique names globally. Let's create your first bucket on Amazon S3.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.*;

 public void createBucket(String bucketName) {
    try {
        CreateBucketRequest createBucketRequest = CreateBucketRequest.builder()
                .bucket(bucketName)
                .build();
        CreateBucketResponse createBucketResponse = s3Client.createBucket(createBucketRequest);
        boolean successful = createBucketResponse.sdkHttpResponse()
                .isSuccessful();
        if (successful) {
            String location = createBucketResponse.location();
            System.out.println(&amp;quot;Bucket created successfully at : &amp;quot; + location);
        } else System.out.println(&amp;quot;Unable to create bucket&amp;quot;);
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Listing All Buckets Using S3Client&lt;/h2&gt;
&lt;hr/&gt;

&lt;p&gt;Using the S3Client, you can retrieve a list of all buckets in your configured region. The &lt;code&gt;listBuckets()&lt;/code&gt; method provides this functionality.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.*;

 public void listBucketObjects() {
    try {
        ListBucketsResponse listBucketsResponse = s3Client.listBuckets();
        listBucketsResponse.buckets()
                .stream()
                .forEach(bucket -&amp;gt; System.out.println(&amp;quot;bucket : &amp;quot; + bucket.name()));
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Deleting Empty Buckets with S3Client&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;To delete a bucket on Amazon S3, use the &lt;code&gt;deleteBucket()&lt;/code&gt; method of the S3Client. However, the bucket must be empty before deletion; otherwise, the AWS SDK will throw an exception&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.*;

 public boolean deleteEmptyBucket(String bucketName) {
    try {
        DeleteBucketRequest deleteBucketRequest = DeleteBucketRequest.builder()
                .bucket(bucketName)
                .build();
        DeleteBucketResponse deleteBucketResponse = s3Client.deleteBucket(deleteBucketRequest);
        boolean successful = deleteBucketResponse.sdkHttpResponse()
                .isSuccessful();
        System.out.println(&amp;quot;is bucket deleted : &amp;quot; + successful);
        return successful;
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
        return false;
    }
 }&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;When deleting an S3 bucket using the AWS SDK for Java, a &lt;code&gt;software.amazon.awssdk.services.s3.model.S3Exception&lt;/code&gt; is thrown if the bucket is not empty. This exception signifies a validation error and prevents accidental deletion of buckets with content.(alert-error)&lt;/blockquote&gt;&lt;br/&gt;

&lt;h2&gt;Deleting Unversioned, Non-Empty S3 Buckets with S3Client&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;If you have a non-empty bucket without versioning enabled, you'll need to delete its contents before deleting the bucket itself. To do this, list all the objects in the bucket and then delete them individually.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.*;

 public boolean deleteUnversionedBucket(String bucketName) {
    try {
        // Before you can delete an Amazon S3 bucket, you must ensure that the bucket is empty or an error will result.
        // If you have a versioned bucket, you must also delete any versioned objects associated with the bucket.
        ListObjectsRequest listObjectsRequest = ListObjectsRequest.builder()
                .bucket(bucketName)
                .build();
        ListObjectsResponse listObjectsResponse = s3Client.listObjects(listObjectsRequest);
        listObjectsResponse.contents()
                .stream()
                // create a DeleteObjectRequest
                .map(s3Object -&amp;gt; DeleteObjectRequest.builder()
                        .bucket(bucketName)
                        .key(s3Object.key())
                        .build())
                // delete objects
                .forEach(deleteObjectRequest -&amp;gt; s3Client.deleteObject(deleteObjectRequest));

        // once all the objects in a bucket deleted successfully, we can delete empty bucket.
        return deleteEmptyBucket(bucketName);
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
        return false;
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Deleting a Versioned Non-Empty S3 Bucket with S3Client&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;If versioning is enabled for your bucket, you must delete all versioned objects individually before deleting the bucket itself. Attempting to delete a versioned bucket directly will result in an S3Exception.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.*;

 public boolean deleteVersionedBucket(String bucketName) {
    try {
        // Before you can delete an Amazon S3 bucket, you must ensure that the bucket is empty or an error will result.
        // If you have a versioned bucket, you must also delete any versioned objects associated with the bucket.
        ListObjectVersionsRequest listObjectVersionsRequest = ListObjectVersionsRequest.builder()
                .bucket(bucketName)
                .build();
        ListObjectVersionsResponse listObjectVersionsResponse = s3Client.listObjectVersions(listObjectVersionsRequest);
        listObjectVersionsResponse.versions()
                .stream()
                .peek(objectVersion -&amp;gt; System.out.println(&amp;quot;versionid: &amp;quot; + objectVersion.versionId() +
                        &amp;quot; key: &amp;quot; + objectVersion.key()))
                // create a DeleteObjectRequest
                .map(objectVersion -&amp;gt; DeleteObjectRequest.builder()
                        .bucket(bucketName)
                        .key(objectVersion.key())
                        .versionId(objectVersion.versionId())
                        .build())
                // delete objets one by one
                .forEach(deleteObjectRequest -&amp;gt; s3Client.deleteObject(deleteObjectRequest));

        // once all the objects in a bucket deleted successfully, we can delete empty bucket.
        return deleteEmptyBucket(bucketName);
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
        return false;
    }
 }&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;The AWS SDK for Java throws a &lt;code&gt;software.amazon.awssdk.services.s3.model.S3Exception&lt;/code&gt; when deleting a bucket that contains versioned objects. This exception highlights the requirement to delete all versions within the bucket before deletion can be successful.(alert-error)&lt;/blockquote&gt;&lt;br/&gt;

&lt;h2&gt;Removing S3 Website Bucket Configuration Using S3Client&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Amazon S3 can serve as a static website host. While you cannot directly delete a bucket hosting a static website, you can remove its static website configuration.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;If the specified bucket doesn't exist, Amazon S3 returns a 404 error code. Upon successfully deleting the bucket's static website configuration, it returns a 200 success code.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.*;

 public boolean deleteBucketWebsite(String bucketName) {
    try {
        DeleteBucketWebsiteRequest deleteBucketWebsiteRequest = DeleteBucketWebsiteRequest.builder()
                .bucket(bucketName)
                .build();
        DeleteBucketWebsiteResponse deleteBucketWebsiteResponse = s3Client.deleteBucketWebsite(deleteBucketWebsiteRequest);
        boolean successful = deleteBucketWebsiteResponse.sdkHttpResponse()
                .isSuccessful();
        System.out.println(&amp;quot;Is S3 Website Bucket Deleted : &amp;quot; + successful);
        return successful;
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
        return false;
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;This tutorial has provided a foundational understanding of Amazon S3 bucket operations using the Spring Cloud AWS library. We've explored essential tasks like creating buckets, listing their contents, and effectively deleting them, both with and without versioning enabled.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Additionally, we've delved into the process of removing static website configurations from buckets and have become familiar with common S3Exception scenarios that may arise during development.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Want to know how to efficiently store your files in the cloud? Explore our guide on &lt;a href="https://www.learnjavaskills.in/2024/10/spring-cloud-aws-s3-file-upload.html"&gt;(getButton) #text=(uploading files to Amazon S3) #icon=(link) #color=(#35a576)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-s3" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;</content><link href="https://www.learnjavaskills.in/feeds/2784209087088086656/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/09/spring-cloud-aws-s3-bucket-operations.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/2784209087088086656" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/2784209087088086656" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/09/spring-cloud-aws-s3-bucket-operations.html" rel="alternate" title="Spring Cloud AWS S3 Bucket Operations (Create, List, Delete)" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO_KblFRLuMG6eAxL5wbDhcUBV3SKM3XWog7vARqUTXxDeNsbh3yTwfv9oyiKbultTQyDXiv0fRfSOZ-Gb4O2vZqpN68tB9_hHYQaK1BaxD-MeWSZPT9V8pKbDjSaz7s3Rat6Sg9v-66M7yxkA3dAkoGZpwzVWHFMBxkadTWq3V5oniCa6dOu-vOF2icPe/s72-c/Spring%20cloud%20Aws.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-6251108540728196355</id><published>2024-09-21T16:58:00.000+05:30</published><updated>2024-09-21T16:58:04.883+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">How to Create Presigned URLs in Spring Cloud AWS for S3 Storage</title><content type="html">&lt;p&gt;Amazon S3 buckets are initially private, meaning they cannot be accessed publicly. To temporarily grant others access to specific objects, you can create S3 presigned URLs.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;These URLs provide limited, time-bound access to the object, allowing you to share the content securely for a specific period&lt;/p&gt;&lt;br&gt;

&lt;p&gt;Presigned URLs can be created for both downloads (using the GET HTTP method) and uploads (using the PUT HTTP method).&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This allows you to securely share files for downloading or accepting uploads from others within a specified timeframe&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;In this tutorial, we'll demonstrate how to grant temporary access to S3 bucket objects using Spring Cloud AWS S3 within a Spring Boot application.&lt;/p&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-s3" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHvuzhQZ0KUc0uFa8GeavNuLVakKVW_4VUj-LwbT4_AwFvVd2XnEBDQDiz1VWJ7OwPGjUwJSOaQZ9eNclr94pLGSdxVreBiZ-Z2q_24NGsCb_Q_u7Fw5Nlo2EFfr-wclJmM5kw2vKg5einnB-AeO66_8hRdtaHvEyOjmXH-ufOys6l8-bnEP4xPalVke4L/s1600/Spring%20cloud%20Aws.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="How to Create Presigned URLs in Spring Cloud AWS for S3 Storage" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHvuzhQZ0KUc0uFa8GeavNuLVakKVW_4VUj-LwbT4_AwFvVd2XnEBDQDiz1VWJ7OwPGjUwJSOaQZ9eNclr94pLGSdxVreBiZ-Z2q_24NGsCb_Q_u7Fw5Nlo2EFfr-wclJmM5kw2vKg5einnB-AeO66_8hRdtaHvEyOjmXH-ufOys6l8-bnEP4xPalVke4L/s1600/Spring%20cloud%20Aws.png"/&gt;&lt;/a&gt;&lt;/div&gt;


&lt;strike&gt;toc&lt;/strike&gt;
&lt;br/&gt;

&lt;h2&gt;Dependencies&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;To get started with this tutorial, you'll need to add the following dependencies to your Spring Boot project's. This dependency provides the necessary components for interacting with AWS services, including S3.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Gradle&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "groovy"&gt;ext {
    springCloudAwsVersion = &amp;#39;3.0.0&amp;#39;
}

dependencies {
    // spring cloud aws BOM(Bill of materials)
    implementation platform(&amp;quot;io.awspring.cloud:spring-cloud-aws-dependencies:${springCloudAwsVersion}&amp;quot;)
    implementation &amp;#39;io.awspring.cloud:spring-cloud-aws-starter-s3&amp;#39;
    // AWS launched a high level file transfer utility, called Transfer Manager and a CRT based S3 client.
    // The starter automatically configures and registers a software.amazon.awssdk.transfer.s3.S3TransferManager bean if the following dependency is added to the project:
    implementation &amp;#39;software.amazon.awssdk:s3-transfer-manager&amp;#39;
    //Transfer Manager works the best with CRT S3 Client. To auto-configure CRT based S3AsyncClient add following dependency to your project:
    implementation &amp;#39;software.amazon.awssdk.crt:aws-crt&amp;#39;
}&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;h3&gt;Maven&lt;/h3&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;io.awspring.cloud&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-cloud-aws-starter-s3&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
	
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;software.amazon.awssdk&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;s3-transfer-manager&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
	
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;software.amazon.awssdk.crt&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;aws-crt&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;

&amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;io.awspring.cloud&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-cloud-aws-dependencies&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;{project-version}&amp;lt;/version&amp;gt;
            &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
            &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
       &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
&amp;lt;/dependencyManagement&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Configuration and Credentials&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Before diving into bucket operations, let's configure our Spring Boot application to interact with AWS S3. Spring Cloud AWS offers auto-configuration for &lt;u&gt;S3Client, S3TransferManager, and S3Template&lt;/u&gt;, making setup a breeze.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Here's what you need to add to your &lt;code&gt;application.properties&lt;/code&gt; file:&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "properties"&gt; # s3 Configuration
 spring.cloud.aws.credentials.access-key=
 spring.cloud.aws.credentials.secret-key=
 # Configures endpoint used by S3Client, I&amp;#39;m woorking in the Asia Pacific (Mumbai) hence, I&amp;#39;ve configure ap-south1 region and endpoint
 spring.cloud.aws.s3.endpoint=https://s3.ap-south-1.amazonaws.com
 spring.cloud.aws.region.static=ap-south-1&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;IAM Permissions for Creating Presigned URLs&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;To follow this tutorial, your IAM user must have the &lt;code&gt;s3:GetObject&lt;/code&gt; and &lt;code&gt;s3:PutObject&lt;/code&gt; permissions.&lt;/p&gt;&lt;br/&gt;
  
  &lt;p&gt;You might be wondering why these permissions are necessary if presigned URLs are used to grant access to non-S3 bucket owners. The answer is that presigned URLs can only be generated by someone who already has access to the underlying object.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "json"&gt; {
    &amp;quot;Version&amp;quot;: &amp;quot;2012-10-17&amp;quot;,
    &amp;quot;Statement&amp;quot;: [
        {
            &amp;quot;Sid&amp;quot;: &amp;quot;DownloadObject&amp;quot;,
            &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
            &amp;quot;Action&amp;quot;: &amp;quot;s3:GetObject&amp;quot;,
            &amp;quot;Resource&amp;quot;: &amp;quot;arn:aws:s3:::*/*&amp;quot;
        },
        {
            &amp;quot;Sid&amp;quot;: &amp;quot;UploadObject&amp;quot;,
            &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
            &amp;quot;Action&amp;quot;: &amp;quot;s3:PutObject&amp;quot;,
            &amp;quot;Resource&amp;quot;: &amp;quot;arn:aws:s3:::*/*&amp;quot;
        }
    ]
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;


&lt;h2&gt;Creating Presigned URLs for GET Requests with S3Presigner&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Let's create our first presigned URL for a &lt;b&gt;GET&lt;/b&gt; request using the &lt;code&gt;S3Presigner&lt;/code&gt;. Before we begin, ensure you have an active S3 bucket and an object within it.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;In this example, I'll use a bucket named &lt;u&gt;"learnjavaskills" with an index.html file&lt;/u&gt;. We'll generate a URL to download this file.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import io.awspring.cloud.s3.S3Exception;
 import software.amazon.awssdk.services.s3.model.GetObjectRequest;
 import software.amazon.awssdk.services.s3.presigner.S3Presigner;
 import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
 import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;

 public URL createPreSignedUrlUsingS3PresignerForGetRequest(String bucketName, String key) {
    try {
        GetObjectRequest objectRequest = GetObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();

        GetObjectPresignRequest objectPresignRequest = GetObjectPresignRequest.builder()
                .signatureDuration(Duration.ofMinutes(10)) // URL will expire after 10 minutes
                .getObjectRequest(objectRequest)
                .build();
        PresignedGetObjectRequest presignedGetObjectRequest = s3Presigner.presignGetObject(objectPresignRequest);

        URL url = presignedGetObjectRequest.url();
        System.out.println(&amp;quot;presigned url : &amp;quot; + url.toString());
        return url;
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
        return null;
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;code&gt;S3Presigner&lt;/code&gt; : is an interface that allows you to sign an S3 SdkRequest, enabling it to be executed without requiring additional authentication from the caller.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;code&gt;GetObjectRequest&lt;/code&gt; : Retrieves objects from Amazon S3. To use the GET method, you must have READ access to the object. If you grant READ access to the anonymous user, you can retrieve the object without requiring an authorization header.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;code&gt;GetObjectPresignedRequest&lt;/code&gt; : A request to create a presigned URL for a &lt;u&gt;GetObjectRequest&lt;/u&gt;, allowing it to be executed at a later time without requiring additional signing or authentication.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;Downloading Files Using Presigned URLs with Postman&lt;/h3&gt;

&lt;p&gt;Once you have the presigned URL, let's use Postman to download the object from the S3 bucket. As you'll see in the response, you can successfully read the index.html file without providing any credentials.&lt;/p&gt;&lt;br/&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF4ALcEQ0-L1Da6B8Pu1C89uJZ9sBoJLPPKTnYZr8XXujwQRmYi5c1zPug1-SHpq1hU-jsdOISGyvxNKOZ43flGd21sOJaC8yBIWDWKdzdvgW4ed4dFsAqh8o2lgzlVBc_GHrRnwg3EvT8pVDoGx6NrjnAkXmFvFxpmMzzNX5MWaU-9rTC73R3DYTBNcQg/s1600/s3-client-get-method.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="downloading file using presigned url" border="0" data-original-height="416" data-original-width="940" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF4ALcEQ0-L1Da6B8Pu1C89uJZ9sBoJLPPKTnYZr8XXujwQRmYi5c1zPug1-SHpq1hU-jsdOISGyvxNKOZ43flGd21sOJaC8yBIWDWKdzdvgW4ed4dFsAqh8o2lgzlVBc_GHrRnwg3EvT8pVDoGx6NrjnAkXmFvFxpmMzzNX5MWaU-9rTC73R3DYTBNcQg/s1600/s3-client-get-method.png"/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br/&gt;

&lt;h3&gt;Presigned URL Expiration Responses&lt;/h3&gt;

&lt;p&gt;The presigned URL we created has a validity of only 10 minutes. If a user attempts to download the file after this interval, Amazon S3 will deny access&lt;/p&gt;&lt;br/&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSvvjVrQgMaK-wzp5anj9HH4m_NjhiSeMpMM0ALoBQuxPl2GsEbNnixxXUrYdRBlvd5Z2uGtavDfQmCHORJUu14_7NcmAVZ01LnFZzHF89OPDDKjSHzZrghaykbU9P3YAYCLBquKrGVcp_cXFEKdQ4RLjcMqAbRmwlrzcwidFj0osaxZa6Q_7f1t915Wck/s1600/access-denied-expire-url.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="presigned url expired" border="0" data-original-height="428" data-original-width="926" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSvvjVrQgMaK-wzp5anj9HH4m_NjhiSeMpMM0ALoBQuxPl2GsEbNnixxXUrYdRBlvd5Z2uGtavDfQmCHORJUu14_7NcmAVZ01LnFZzHF89OPDDKjSHzZrghaykbU9P3YAYCLBquKrGVcp_cXFEKdQ4RLjcMqAbRmwlrzcwidFj0osaxZa6Q_7f1t915Wck/s1600/access-denied-expire-url.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br/&gt;

&lt;h2&gt;Creating Presigned URLs for GET Requests with S3Template&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;S3Template is a high-level API provided by Spring Cloud AWS that simplifies interactions with Amazon S3. It offers a convenient way to perform common operations like creating, deleting, and managing buckets and objects.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&lt;b&gt;S3Template&lt;/b&gt; significantly simplifies the process of creating presigned URLs. By calling the &lt;code&gt;createSignedGetUrl&lt;/code&gt; method, you can easily generate a presigned URL for a specified bucket, object key, and duration, allowing you to securely share access to your S3 objects&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import io.awspring.cloud.s3.S3Exception;
 import io.awspring.cloud.s3.S3Template;

 public URL createPreSignedUrlUsingS3TemplateForGetRequest(String bucketName, String key) {
    try {
        return s3Template.createSignedGetURL(bucketName, key, Duration.ofMinutes(10));
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
        return null;
    }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;Downloading Files Using Presigned URLs with Postman&lt;/h3&gt;

&lt;p&gt;I've created a presigned URL for an image. Let's verify its functionality by downloading the image.&lt;/p&gt;&lt;br/&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDHgeT5Gk96Cx5WGCOQSgj2BuVAOe-po73iZS3Oy5HutKeGc4TSiDqVp64D1TC6iLlnVjIRvSz_J3H2gnSQAlU37Dfm_MjfUATKEc90pLOWEsdHhLSLYzCenbCN8DbDetUk3qy4rHCUTKZgespuR42_WYZfCP39iuRoR4Lc50Rtbq6RrHF3oHe16YVJss1/s1600/s3Template-get-method.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="downloading file using presigned url" border="0" data-original-height="540" data-original-width="937" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDHgeT5Gk96Cx5WGCOQSgj2BuVAOe-po73iZS3Oy5HutKeGc4TSiDqVp64D1TC6iLlnVjIRvSz_J3H2gnSQAlU37Dfm_MjfUATKEc90pLOWEsdHhLSLYzCenbCN8DbDetUk3qy4rHCUTKZgespuR42_WYZfCP39iuRoR4Lc50Rtbq6RrHF3oHe16YVJss1/s1600/s3Template-get-method.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br/&gt;

&lt;h2&gt;Creating Presigned URLs for PUT Requests with S3Presigner&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Similarly, we can create a presigned URL for uploading objects to Amazon S3. In this case, we'll need to use a &lt;b&gt;PUT&lt;/b&gt; request.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Let's explore how to create a presigned URL for a PUT request using S3Presigner.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;To create a presigned URL for uploading a file, we can use the &lt;code&gt;presignPutObject&lt;/code&gt; method of the &lt;b&gt;S3Presigner&lt;/b&gt; interface.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import io.awspring.cloud.s3.S3Exception;
 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
 import software.amazon.awssdk.services.s3.presigner.S3Presigner;
 import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest;
 import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;

 public URL createPreSignedUrlUsingS3PresignerForPutRequest(String bucketName, String key) {
    try {
        PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();
        PutObjectPresignRequest putObjectPresignRequest = PutObjectPresignRequest.builder()
                .signatureDuration(Duration.ofMinutes(10)) // URL will expire after 10 minutes
                .putObjectRequest(putObjectRequest)
                .build();

        PresignedPutObjectRequest presignedPutObjectRequest = s3Presigner.presignPutObject(putObjectPresignRequest);
        URL url = presignedPutObjectRequest.url();
        System.out.println(&amp;quot;presigned url : &amp;quot; + url.toString());
        return  url;
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
        return null;
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;code&gt;PutObjectRequest&lt;/code&gt; : Uploads a new object to the specified Amazon S3 bucket. It can also optionally upload object metadata and set a canned access control policy for the new object.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;code&gt;PutObjectPresignRequest&lt;/code&gt; : A request to pre-sign a PutObjectRequest so that it can be executed at a later time without requiring additional signing or authentication.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Uploading Files Using Presigned URLs with Postman&lt;/h3&gt;

&lt;p&gt;Let's verify if the upload presigned URL works by using Postman. Ensure that you set the HTTP method to PUT.&lt;/p&gt;&lt;br/&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSuNRtk4igom5fNjamwSDZce5sDPJbt-B27tOymCcnfDdyu2ka_2vS4IGdxZyFAfbIhejQb_aUJvXUSBxCzWCWmZUiSCMFzjXPWeX0AnQkDSjVLDBsDo7b35qV7rnyBHRi6QUX6OE8-a0T5gT5QFKyH9TPRDMTKlvG4l9_yrC9uoeglKRmD3H8z-IoCSK2/s1600/upload-file.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Uploading Files Using Presigned URLs with Postman" border="0" data-original-height="408" data-original-width="925" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSuNRtk4igom5fNjamwSDZce5sDPJbt-B27tOymCcnfDdyu2ka_2vS4IGdxZyFAfbIhejQb_aUJvXUSBxCzWCWmZUiSCMFzjXPWeX0AnQkDSjVLDBsDo7b35qV7rnyBHRi6QUX6OE8-a0T5gT5QFKyH9TPRDMTKlvG4l9_yrC9uoeglKRmD3H8z-IoCSK2/s1600/upload-file.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br/&gt;

&lt;h2&gt;Creating Presigned URLs for PUT Requests with S3Template&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Spring Cloud AWS simplifies the process of creating presigned URLs for PUT requests.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;By using the &lt;code&gt;createSignedPutUrl&lt;/code&gt; method of &lt;b&gt;S3Template&lt;/b&gt;, you can easily generate a presigned URL for uploading objects to your S3 bucket, &lt;u&gt;specifying the bucket name, object key, and desired duration of validity&lt;/u&gt;.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; import io.awspring.cloud.s3.S3Exception;
 import io.awspring.cloud.s3.S3Template;

 public URL createPreSignedUrlUsingS3TemplateForPutRequest(String bucketName, String key) {
	try {
            return s3Template.createSignedPutURL(bucketName, key, Duration.ofMinutes(10));
	} catch (S3Exception s3Exception) {
		s3Exception.printStackTrace();
            return null;
	}
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Conclussion&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;In this blog tutorial, we've explored the concept of presigned URLs and their significance in securely sharing access to S3 objects. We've learned how to create presigned URLs for both GET (download) and PUT (upload) requests using both S3Presigner and S3Template.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;By leveraging presigned URLs, you can grant temporary access to specific S3 objects, enabling you to share files or data securely with external parties without compromising your account's security.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This is particularly useful in scenarios where you need to provide controlled access to sensitive information or collaborate with external teams.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Remember to carefully manage the duration of your presigned URLs to ensure that access is limited to the necessary timeframe.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;By following the guidelines and examples provided in this tutorial, you can effectively utilize presigned URLs to enhance the security and flexibility of your S3-based applications.&lt;/p&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-s3" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;
</content><link href="https://www.learnjavaskills.in/feeds/6251108540728196355/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/09/amazon-s3-presigned-url-spring-cloud-aws.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/6251108540728196355" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/6251108540728196355" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/09/amazon-s3-presigned-url-spring-cloud-aws.html" rel="alternate" title="How to Create Presigned URLs in Spring Cloud AWS for S3 Storage" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHvuzhQZ0KUc0uFa8GeavNuLVakKVW_4VUj-LwbT4_AwFvVd2XnEBDQDiz1VWJ7OwPGjUwJSOaQZ9eNclr94pLGSdxVreBiZ-Z2q_24NGsCb_Q_u7Fw5Nlo2EFfr-wclJmM5kw2vKg5einnB-AeO66_8hRdtaHvEyOjmXH-ufOys6l8-bnEP4xPalVke4L/s72-c/Spring%20cloud%20Aws.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-7138682907479516013</id><published>2024-09-02T20:26:00.000+05:30</published><updated>2024-09-02T20:26:25.269+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">How to Use AWS DynamoDB BatchWriteItem and BatchGetItem in Java Spring Boot Applications | Learn Java Skills</title><content type="html">&lt;p&gt;AWS DynamoDB's BatchWriteItem and BatchGetItem operations offer efficient ways to interact with multiple items in a single request, enhancing performance and reducing network overhead compared to individual item operations.&lt;/p&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-dynamodb" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;strike&gt;toc&lt;/strike&gt;


&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjK6ofWO3ya6yxeUVEnV7OMylVPyUX2yeFlZ60i9lk7jd4lSik12tg0IXeIZDekToriznPWu2JydLTDIdgMFxhzQcn7ZcnMrmhh1bGkzRkdx2lXD3Yzagczj1DqSvKuFJWae5318QgjVqQDzUVjvbkmOH9Gt6ovfwaskUEnrVHyZAPGP15ADHisgtaRBID/s1600/BatchWriteItem-and-BatchGetItem.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="batchwriteitem and batchgetitem thumbnail image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjK6ofWO3ya6yxeUVEnV7OMylVPyUX2yeFlZ60i9lk7jd4lSik12tg0IXeIZDekToriznPWu2JydLTDIdgMFxhzQcn7ZcnMrmhh1bGkzRkdx2lXD3Yzagczj1DqSvKuFJWae5318QgjVqQDzUVjvbkmOH9Gt6ovfwaskUEnrVHyZAPGP15ADHisgtaRBID/s1600/BatchWriteItem-and-BatchGetItem.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;h2&gt;Interacting with DynamoDB Using Java&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;The AWS SDK for Java provides interface like &lt;code&gt;DynamoDbClient&lt;/code&gt; and &lt;code&gt;DynamoDbAsyncClient&lt;/code&gt; to interact with the DynamoDB database. These clients offer methods for various DynamoDB operations, including &lt;code&gt;getItem&lt;/code&gt;, &lt;code&gt;putItem&lt;/code&gt;, &lt;code&gt;batchGetItem&lt;/code&gt;, and &lt;code&gt;batchWriteItem&lt;/code&gt;&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Spring Boot simplifies DynamoDB interaction by auto-configuring the DynamoDbClient based on settings in your application properties file when using the Spring Cloud AWS Starter DynamoDB&lt;/p&gt;&lt;br/&gt;

&lt;h2&gt;Dependencies: Gradle&lt;/h2&gt;
&lt;hr&gt;

&lt;pre&gt;&lt;code class = "groovy"&gt; // spring cloud aws BOM(Bill of materials)
 implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:${springCloudAwsVersion}")
 // dynamoDB
 implementation 'io.awspring.cloud:spring-cloud-aws-starter-dynamodb'&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;Setting Up DynamoDB for Your Application: application.properties&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;If you're new to Spring Cloud AWS and DynamoDB, I recommend reading our &lt;a href="https://www.learnjavaskills.in/2024/04/spring-cloud-aws-dynamodb.html"&gt;(getButton) #text=(Spring Boot, DynamoDB, and Spring Cloud AWS: A Step-by-Step Tutorial) #icon=(link) #color=(#35a576)&lt;/a&gt;, which will help you build up your project and get deep into the CRUD (Create, Read, Update, and Delete) operations.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "properties"&gt; spring.application.name=spring-cloud-aws-dynamodb

 # DynamoDB connection
 spring.cloud.aws.credentials.access-key=
 spring.cloud.aws.credentials.secret-key=
 # Choose your region according to your table. Because I have a DynamoDB table in the ap-south-1 area, I've set the endpoint and region.
 spring.cloud.aws.region.static=ap-south-1
 spring.cloud.aws.endpoint=https://dynamodb.ap-south-1.amazonaws.com&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h2&gt;DynamoDB BatchWriteItem: Efficiently Writing Multiple Items to DynamoDB&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;The &lt;code&gt;BatchWriteItem&lt;/code&gt; approach &lt;b&gt;puts&lt;/b&gt; or &lt;b&gt;deletes&lt;/b&gt; multiple items into one or more tables. A single call to BatchWriteItem may send up to &lt;b&gt;16MB&lt;/b&gt; of data across the network, which includes up to &lt;b&gt;25 item&lt;/b&gt; put or delete operations.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;While individual items can be up to &lt;b&gt;400 KB&lt;/b&gt; once saved, it's crucial to remember that an item's representation may be bigger than 400 KB when submitted in DynamoDB's JSON format for the API request.&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;BatchWriteItem&lt;/code&gt; cannot update items. If you run a BatchWriteItem action on an existing item, &lt;u&gt;the operation will overwrite the item's values&lt;/u&gt;, making it look as if it was changed. To update things, AWS recommend using the &lt;code&gt;UpdateItem&lt;/code&gt; action.(alert-warning)&lt;/blockquote&gt;

&lt;h3&gt;Java Program to Perform BatchWriteItems Operations on DynamoDB&lt;/h3&gt;

&lt;p&gt;This Java program demonstrates how to efficiently insert data into multiple DynamoDB tables using the &lt;code&gt;BatchWriteItem&lt;/code&gt; operation. We'll create sample data for &lt;code&gt;Orders&lt;/code&gt; and &lt;code&gt;products&lt;/code&gt; tables and insert them in a single batch for improved performance.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt;package in.learnjavaskills.springcloudawsdynamodb.service;

import org.springframework.stereotype.Service;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class BatchItemExample
{
    private final DynamoDbClient dynamoDbClient;

    public BatchItemExample(DynamoDbClient dynamoDbClient) {
        this.dynamoDbClient = dynamoDbClient;
    }

    public void batchWriteItem() {
        Map&amp;lt;String, AttributeValue&amp;gt; productsMap = new HashMap&amp;lt;&amp;gt;();
        productsMap.put(&amp;quot;product_id&amp;quot;, AttributeValue.fromS(&amp;quot;pd_12345&amp;quot;));
        productsMap.put(&amp;quot;product_name&amp;quot;, AttributeValue.fromS(&amp;quot;Laptop&amp;quot;));
        productsMap.put(&amp;quot;description&amp;quot;, AttributeValue.fromS(&amp;quot;14 inch screen laptop&amp;quot;));
        productsMap.put(&amp;quot;price&amp;quot;, AttributeValue.fromN(&amp;quot;49.87&amp;quot;));
        productsMap.put(&amp;quot;stock&amp;quot;, AttributeValue.fromN(&amp;quot;101&amp;quot;));

        PutRequest productsPutRequest = PutRequest.builder().item(productsMap).build();
        WriteRequest productsWriteRequest = WriteRequest.builder().putRequest(productsPutRequest).build();

        Map&amp;lt;String, AttributeValue&amp;gt; ordersMap = new HashMap&amp;lt;&amp;gt;();
        ordersMap.put(&amp;quot;order_id&amp;quot;, AttributeValue.fromS(&amp;quot;od_12345&amp;quot;));
        ordersMap.put(&amp;quot;customer_id&amp;quot;, AttributeValue.fromS(&amp;quot;c_12345&amp;quot;));
        ordersMap.put(&amp;quot;product_id&amp;quot;, AttributeValue.fromS(&amp;quot;pd_12345&amp;quot;));
        ordersMap.put(&amp;quot;order_date&amp;quot;, AttributeValue.fromS(LocalDate.now().toString()));

        PutRequest orderPutRequest = PutRequest.builder().item(ordersMap).build();
        WriteRequest orderWriteRequest = WriteRequest.builder().putRequest(orderPutRequest).build();

        Map&amp;lt;String, List&amp;lt;WriteRequest&amp;gt;&amp;gt; writeRequestMap = new HashMap&amp;lt;&amp;gt;();
        writeRequestMap.put(&amp;quot;products&amp;quot;, Arrays.asList(productsWriteRequest));
        writeRequestMap.put(&amp;quot;Orders&amp;quot;, Arrays.asList(orderWriteRequest));

        BatchWriteItemRequest batchWriteItemRequest = BatchWriteItemRequest.builder().requestItems(writeRequestMap).build();

        BatchWriteItemResponse batchWriteItemResponse = dynamoDbClient.batchWriteItem(batchWriteItemRequest);

        // Implement a retry mechanism for batchWriteItem operations that encounter errors.
        while (!batchWriteItemResponse.unprocessedItems().isEmpty()) {
            Map&amp;lt;String, List&amp;lt;WriteRequest&amp;gt;&amp;gt; unprocessedItems = batchWriteItemResponse.unprocessedItems();
            batchWriteItemRequest
                    = BatchWriteItemRequest.builder().requestItems(unprocessedItems).build();
            batchWriteItemResponse = dynamoDbClient.batchWriteItem(batchWriteItemRequest);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;Understanding BatchWriteItemRequest&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;batchWriteItem()&lt;/code&gt; method in the &lt;b&gt;DynamoDBClient&lt;/b&gt; allows you to perform multiple write operations (puts or deletes) across one or more tables in a single request. You provide a &lt;code&gt;BatchWriteItemRequest&lt;/code&gt; object to specify the items and actions to be performed.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The &lt;code&gt;requestItems()&lt;/code&gt; method in a &lt;code&gt;BatchWriteItemRequest&lt;/code&gt; class defines the data to be written to DynamoDB. It takes a map where each key is a DynamoDB table name and the corresponding value is a list of &lt;code&gt;WriteRequest&lt;/code&gt; operations (put or delete) to be performed on that table.&lt;/p&gt;&lt;br/&gt;

&lt;h4&gt;Handling Unprocessed Items: Retrying BatchWriteItem Operations&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;unprocessedItems()&lt;/code&gt; is a response parameter returned by the DynamoDB &lt;b&gt;BatchWriteItemRequest&lt;/b&gt; operation. It contains a list of items that couldn't be processed due to reasons like exceeding provisioned throughput or internal processing errors.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Essentially, it's a mechanism for handling failed write operations. You can retry these unprocessed items in subsequent &lt;b&gt;BatchWriteItemRequest&lt;/b&gt; until all items are successfully written to DynamoDB.&lt;/p&gt;

&lt;blockquote&gt;If the requested data exceeds these limits, or if there's insufficient table capacity, or an internal error occurs, the operation might return only a portion of the results. In such cases, the system provides information about the &lt;code&gt;UnprocessedKeys&lt;/code&gt;, allowing you to retry the operation to retrieve the remaining data.(alert-passed)&lt;/blockquote&gt;

&lt;blockquote&gt;When DynamoDB returns unprocessed items in a batch operation, it's essential to retry these items. However, to avoid overwhelming the system and increasing the likelihood of success, implement an exponential backoff strategy. This means progressively increasing the delay between retries. By doing so, you reduce the chance of encountering throttling issues and improve the overall reliability of your batch operations.(alert-error)&lt;/blockquote&gt;

&lt;h3&gt;Understanding WriteRequest: Building Blocks for Batch Write Operations&lt;/h3&gt;

&lt;p&gt;A WriteRequest is a container for specifying either a PutItem or DeleteItem operation within a BatchWriteItem request.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;You can only perform one of these operations (Put or Delete) per WriteRequest. If you need to perform both, you'll need separate WriteRequest objects. Each WriteRequest contains either a &lt;code&gt;PutRequest&lt;/code&gt; or a &lt;code&gt;DeleteRequest&lt;/code&gt; object.&lt;/p&gt;&lt;br/&gt;

&lt;h4&gt;PutRequest: Inserting or Updating Items&lt;/h4&gt;

&lt;p&gt;If you want to &lt;b&gt;insert&lt;/b&gt; or &lt;b&gt;update&lt;/b&gt; an item, you use a &lt;code&gt;PutRequest&lt;/code&gt; object within your WriteRequest. A PutRequest contains an &lt;code&gt;Item&lt;/code&gt; method, which is a map representing the item to be put into the table.&lt;/p&gt;&lt;br/&gt;

&lt;h4&gt;DeleteRequest: Removing Items from DynamoDB&lt;/h4&gt;

&lt;p&gt;If you want to &lt;b&gt;delete&lt;/b&gt; an item, you use a &lt;code&gt;DeleteRequest&lt;/code&gt; object within your WriteRequest. A DeleteRequest contains a &lt;code&gt;Key&lt;/code&gt; method, which is a map representing the primary key of the item to be deleted.&lt;/p&gt;&lt;br/&gt;



&lt;h2&gt;DynamoDB BatchGetItems: Efficiently Retrieve Multiple Items&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;You can use the &lt;code&gt;BatchGetItem&lt;/code&gt; operation to fetch data from one or more tables. Specify the items you need by their primary keys, and the operation will return their corresponding attributes.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;A single &lt;b&gt;BatchGetItem&lt;/b&gt; operation can fetch up to &lt;b&gt;100 items&lt;/b&gt; with a maximum data size of &lt;b&gt;16 MB&lt;/b&gt;.&lt;/p&gt;&lt;br/&gt;


  
&lt;h3&gt;Java Program to Perform BatchGetItem Operations on DynamoDB&lt;/h3&gt;

&lt;p&gt;This Java program demonstrates how to efficiently fetch data from two DynamoDB tables, &lt;b&gt;Orders&lt;/b&gt; and &lt;b&gt;products&lt;/b&gt;, using the &lt;code&gt;BatchGetItem&lt;/code&gt; operation. By specifying multiple items and their primary keys within a single request, we can optimize data retrieval performance compared to individual &lt;code&gt;GetItem&lt;/code&gt; operations.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "Java"&gt;package in.learnjavaskills.springcloudawsdynamodb.service;

import org.springframework.stereotype.Service;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class BatchItemExample
{
    private final DynamoDbClient dynamoDbClient;

    public BatchItemExample(DynamoDbClient dynamoDbClient) {
        this.dynamoDbClient = dynamoDbClient;
    }
    
    public void batchGetItem() {

        Map&amp;lt;String, AttributeValue&amp;gt; productsKeys = new HashMap&amp;lt;&amp;gt;();
        productsKeys.put(&amp;quot;product_id&amp;quot;, AttributeValue.fromS(&amp;quot;pd_12345&amp;quot;));
        productsKeys.put(&amp;quot;product_name&amp;quot;, AttributeValue.fromS(&amp;quot;Laptop&amp;quot;));

        Map&amp;lt;String, AttributeValue&amp;gt; ordersKeys = new HashMap&amp;lt;&amp;gt;();
        ordersKeys.put(&amp;quot;order_id&amp;quot;, AttributeValue.fromS(&amp;quot;od_12345&amp;quot;));
        ordersKeys.put(&amp;quot;customer_id&amp;quot;, AttributeValue.fromS(&amp;quot;c_12345&amp;quot;));

        Map&amp;lt;String, KeysAndAttributes&amp;gt; requestItems = new HashMap&amp;lt;&amp;gt;();
        KeysAndAttributes productsKeysAndAttributes = KeysAndAttributes.builder().consistentRead(false)
                .keys(productsKeys).build();
        requestItems.put(&amp;quot;products&amp;quot;, productsKeysAndAttributes);

        KeysAndAttributes ordersKeysAndAttributes  = KeysAndAttributes.builder()
                .keys(ordersKeys)
                .build();
        requestItems.put(&amp;quot;Orders&amp;quot;, ordersKeysAndAttributes);


        BatchGetItemRequest batchGetItemRequest = BatchGetItemRequest.builder().requestItems(requestItems).build();
        BatchGetItemResponse batchGetItemResponse = dynamoDbClient.batchGetItem(batchGetItemRequest);
        Map&amp;lt;String, List&amp;lt;Map&amp;lt;String, AttributeValue&amp;gt;&amp;gt;&amp;gt; responses = batchGetItemResponse.responses();
        responses.forEach( (table, itemsList) -&amp;gt; {
            System.out.println(&amp;quot;table name: &amp;quot; + table);
            itemsList.forEach( attributesAndValues -&amp;gt; {
                attributesAndValues.forEach( (key, value) -&amp;gt; {
                    System.out.println(&amp;quot;attributes name : &amp;quot; + key + &amp;quot;, attributes value: &amp;quot; + value.s());
                });
            });
        } );

        // Implement a retry mechanism for batchGetItem operations that encounter errors.
        while(!batchGetItemResponse.unprocessedKeys().isEmpty()) {
            Map&amp;lt;String, KeysAndAttributes&amp;gt; unprocessedKeys = batchGetItemResponse.unprocessedKeys();
            batchGetItemRequest = BatchGetItemRequest.builder().requestItems(unprocessedKeys).build();
            batchGetItemResponse = dynamoDbClient.batchGetItem(batchGetItemRequest);
            responses = batchGetItemResponse.responses();
            responses.forEach( (table, itemsList) -&amp;gt; {
                System.out.println(&amp;quot;table name: &amp;quot; + table);
                itemsList.forEach( attributesAndValues -&amp;gt; {
                    attributesAndValues.forEach( (key, value) -&amp;gt; {
                        System.out.println(&amp;quot;attributes name : &amp;quot; + key + &amp;quot;, attributes value: &amp;quot; + value.s());
                    });
                });
            } );
        }
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;Understanding BatchGetItemRequest&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;batchGetItem()&lt;/code&gt; method in the &lt;b&gt;DynamoDBClient&lt;/b&gt; allows you to efficiently retrieve multiple items from one or more tables in a single operation. To specify the items you want to fetch, you create a &lt;code&gt;BatchGetItemRequest&lt;/code&gt; object.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The &lt;code&gt;requestItems()&lt;/code&gt; method within a &lt;b&gt;BatchGetItemRequest&lt;/b&gt; specifies the tables and items to retrieve. It takes a map where the keys are table names, and the values are objects containing information about the items to fetch from that table, such as their primary keys and any projection expressions.&lt;/p&gt;&lt;br/&gt;


&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;By effectively utilizing the &lt;code&gt;BatchWriteItem&lt;/code&gt; and &lt;code&gt;BatchGetItem&lt;/code&gt; operations, you can significantly enhance the efficiency and performance of your DynamoDB interactions. By understanding the core concepts, including &lt;b&gt;WriteRequest&lt;/b&gt;, &lt;b&gt;PutRequest&lt;/b&gt;, &lt;b&gt;DeleteRequest&lt;/b&gt;, and handling unprocessed items, you're well-equipped to optimize your data manipulation strategies.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;To learn more about DynamoDB transactions and how to use TransactWriteItems and TransactGetItems, check out my latest blog post on &lt;a href="https://www.learnjavaskills.in/2024/09/dynamodb-transactions.html"&gt;(getButton) #text=(DynamoDB Transactions with TransactWriteItems and TransactGetItems) #icon=(link) #color=(#35a576)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-dynamodb" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;

</content><link href="https://www.learnjavaskills.in/feeds/7138682907479516013/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/08/dynamodb-batchwriteitem-and-batchgetitem-operations.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/7138682907479516013" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/7138682907479516013" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/08/dynamodb-batchwriteitem-and-batchgetitem-operations.html" rel="alternate" title="How to Use AWS DynamoDB BatchWriteItem and BatchGetItem in Java Spring Boot Applications | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjK6ofWO3ya6yxeUVEnV7OMylVPyUX2yeFlZ60i9lk7jd4lSik12tg0IXeIZDekToriznPWu2JydLTDIdgMFxhzQcn7ZcnMrmhh1bGkzRkdx2lXD3Yzagczj1DqSvKuFJWae5318QgjVqQDzUVjvbkmOH9Gt6ovfwaskUEnrVHyZAPGP15ADHisgtaRBID/s72-c/BatchWriteItem-and-BatchGetItem.png" width="72"/><thr:total>0</thr:total><georss:featurename>Mumbai, Maharashtra, India</georss:featurename><georss:point>19.0759837 72.8776559</georss:point><georss:box>-9.2342501361788472 37.721405899999993 47.386217536178847 108.0339059</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-3648753781869824952</id><published>2024-05-11T20:24:00.005+05:30</published><updated>2024-08-04T16:19:55.181+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">Mastering DynamoDB Data Retrieval: Advanced Scan and Query Operations with Spring Boot and Spring Cloud AWS | Learn Java Skills</title><content type="html">&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyo529jP_FwbL-zkHdNraIXNvZf7YtoOK2F4kD6xnocdgZ6M2L3h9w6a09UfAnh6lQRKNjYTkOXZBgWtZ5GbrAi_OeBCZKlYMDPwbOd3GVtM4RvrEd7fmKT0fzYyVsdUP0AKO2B1aDaEhPgTuBqkhPokK_qkFz9cDpYJn0l3JOtqKVcQ7nICliJaJjeLjx/s1600/thumbnail.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Mastering DynamoDB Data Retrieval: Advanced Scan and Query Operations with Spring Boot and Spring Cloud AWS | Learn Java Skills" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyo529jP_FwbL-zkHdNraIXNvZf7YtoOK2F4kD6xnocdgZ6M2L3h9w6a09UfAnh6lQRKNjYTkOXZBgWtZ5GbrAi_OeBCZKlYMDPwbOd3GVtM4RvrEd7fmKT0fzYyVsdUP0AKO2B1aDaEhPgTuBqkhPokK_qkFz9cDpYJn0l3JOtqKVcQ7nICliJaJjeLjx/s1600/thumbnail.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Amazon DynamoDB, a NoSQL database service, offers unparalleled scalability and flexibility for modern applications. But efficiently retrieving data requires understanding its core read operations: &lt;b&gt;queries&lt;/b&gt; and &lt;b&gt;scans&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;This tutorial dives deep into using Spring Cloud AWS to seamlessly interact with DynamoDB and harness the power of both queries and scans.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;If you're new to Spring Cloud AWS and DynamoDB, I recommend reading our &lt;a href="https://www.learnjavaskills.in/2024/04/spring-cloud-aws-dynamodb.html"&gt;(getButton) #text=(Spring Boot, DynamoDB, and Spring Cloud AWS: A Step-by-Step Tutorial) #icon=(link) #color=(#35a576)&lt;/a&gt;, which will help you build up your project and get deep into the CRUD (Create, Read, Update, and Delete) operations.&lt;/p&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-dynamodb" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt; &lt;br/&gt;

&lt;strike&gt;toc&lt;/strike&gt;
&lt;br/&gt;


&lt;h2&gt;Mastering Scans: Unleashing DynamoDB's Power for Comprehensive Data Retrieval&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Amazon DynamoDB's &lt;code&gt;Scan&lt;/code&gt; operation reads all items from a table or secondary index. By default, a scan operation retrieves all data attributes for each item in a table or index.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;You can use the &lt;code&gt;ProjectionExpression&lt;/code&gt; parameter to restrict Scan from returning all attributes. &lt;code&gt;Scan&lt;/code&gt; always produces a set of results. If no matching items are discovered, the result set is blank.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;DynamoDB's Scan operation fetches data in chunks of &lt;b&gt;1 MB&lt;/b&gt; at most. To refine the results and avoid unnecessary data transfer, you can leverage filter expressions that narrow down the items after they're retrieved but before they're delivered.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Scanning DynamoDB with Spring Cloud AWS: Code Example&lt;/h3&gt;

&lt;p&gt;Ready to unleash the full power of your DynamoDB table? We'll begin by exploring Spring Cloud AWS's Scan operation to extract all its data.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class="java"&gt; public PageIterable&amp;lt;Movie&amp;gt; scanMovieTable() {
     PageIterable&amp;lt;Movie&amp;gt; moviePageIterable = dynamoDbTemplate.scanAll(Movie.class);
     return moviePageIterable;
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;Spring Cloud AWS provides a convenient method called &lt;code&gt;scanAll&lt;/code&gt; within its &lt;code&gt;DynamoDbTemplate&lt;/code&gt; class. This method takes a single argument - the name of the DynamoDB table you want to scan. In our example, we'll use the &lt;b&gt;Movie&lt;/b&gt; class, which represents our data model, to retrieve all items from the specified table.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 void scanTable()
 {
     PageIterable&amp;lt;Movie&amp;gt; moviePageIterable = movieService.scanMovieTable();
     if (Objects.nonNull(moviePageIterable))
     {
         SdkIterable&amp;lt;Movie&amp;gt; items = moviePageIterable.items();
         if (Objects.nonNull(items))
             items.forEach(System.out :: println);
     }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;Targeting Your Data: Filtering DynamoDB Scans with Expressions&lt;/h3&gt;

&lt;p&gt;Filter expressions act as a powerful tool to streamline your scans by specifying conditions that retrieved items must meet. This significantly reduces the data volume returned, improving efficiency and focusing on relevant information.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public PageIterable&amp;#x3C;Movie&amp;#x3E; scanMovieTableWithFilterExpression(String movieTitleBeginWith) {

    // Filter expression is nothing but, It&amp;#x27;s just like a where clause of SQL. Here we are only selecting whose
    // movie_title begin with the given-movie-title(movieTitleBeginWith) like a LIKE operation of SQL.
    Expression expression = Expression.builder()
        .expression(&amp;#x22;begins_with(movie_title, :movie_title)&amp;#x22;)
        .putExpressionValue(&amp;#x22;:movie_title&amp;#x22;, AttributeValue.fromS(movieTitleBeginWith))
        .build();

    ScanEnhancedRequest scanEnhancedRequest = ScanEnhancedRequest.builder()
        .filterExpression(expression) // filter-expression
        .build();
    PageIterable&amp;#x3C;Movie&amp;#x3E; scan = dynamoDbTemplate.scan(scanEnhancedRequest, Movie.class);
    return scan;
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;DynamoDbTemplate offers a &lt;b&gt;scan&lt;/b&gt; method that takes two arguments: a &lt;code&gt;ScanEnhancedRequest&lt;/code&gt; object and the class representing your DynamoDB table (in this case, the Movie class).&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;This approach allows you to specify filtering criteria within the &lt;code&gt;ScanEnhancedRequest&lt;/code&gt; for targeted data retrieval.&lt;/p&gt;&lt;br/&gt;

&lt;h4&gt;Expressions Explained: A Powerful Tool for Data Control&lt;/h4&gt;

&lt;p&gt;Expressions in DynamoDB act as a blueprint for interacting with your data. They can be used for filtering, sorting, and other operations&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The &lt;code&gt;expression&lt;/code&gt; method of the &lt;code&gt;Expression&lt;/code&gt; class allows you to specify a &lt;b&gt;filter expression&lt;/b&gt; as a string. This string can contain placeholders for the actual values you want to filter on. You then use the &lt;code&gt;putExpressionValue&lt;/code&gt; method to define these placeholder values&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Streamlining Scans: Retrieving Only Relevant Data with Projection Expressions&lt;/h3&gt;

&lt;p&gt;For those familiar with SQL, retrieving only specific columns from a table is common practice.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;DynamoDB offers a similar functionality called projection expressions. This allows you to select the exact attributes you need during a scan operation, reducing data transfer and improving efficiency.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public PageIterable&amp;#x3C;Movie&amp;#x3E; scanMovieTableWithProjectionExpression() {

    // ProjectionExpression, If we want to select only selected attributes from the dynamoDB then we can utilize
    // the projection expression, Since we are using the Spring cloud AWS, we can utilize the NestedAttributeName
    // to set the desire attributes name just like below.
    List&amp;#x3C;NestedAttributeName&amp;#x3E; nestedAttributeNameList = new ArrayList&amp;#x3C;&amp;#x3E;();

    // retrieve characters attribute in a result
    nestedAttributeNameList.add(NestedAttributeName.builder()
         .elements(&amp;#x22;characters&amp;#x22;)
         .build());

    // data type of attribute directors is a map, here we are only selecting key = dir2 from the directors attribute.
    nestedAttributeNameList.add(NestedAttributeName.builder()
         .elements(&amp;#x22;directors&amp;#x22;, &amp;#x22;Dir2&amp;#x22;)
         .build());

    ScanEnhancedRequest scanEnhancedRequest = ScanEnhancedRequest.builder()
         .addNestedAttributesToProject(nestedAttributeNameList) // projection-expression
         .build();

     PageIterable&amp;#x3C;Movie&amp;#x3E; scan = dynamoDbTemplate.scan(scanEnhancedRequest, Movie.class);
     return scan;
}&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;p&gt;&amp;#x2022; &lt;b&gt;NestedAttributeName&lt;/b&gt;: In DynamoDB, nested attribute names let you specify how to access data within nested structures. These names are built using a list of strings, where each string represents a level deeper in the nesting.  For top-level attributes (those not nested), you can simply create a list with a single string element&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;In this code example, we're focusing on retrieving just two attributes from the DynamoDB table: &lt;code&gt;characters&lt;/code&gt; and &lt;code&gt;directors&lt;/code&gt;.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Since &lt;b&gt;'directors'&lt;/b&gt; is stored as a map (key-value pairs), we can be even more specific. We can use the projection expression to target only the value associated with a specific key within the 'directors' map.  Here, we're interested in retrieving directors where the key is 'Dir2'.&lt;/p&gt;&lt;br/&gt;

&lt;h2&gt;Leveraging Queries for Efficient Data Retrieval in DynamoDB&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;DynamoDB's Query operation lets you pinpoint items using their primary key values&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;You must specify the partition key attribute's name as well as a single value. Query returns all objects with the specified partition key value. You may also specify a sort key attribute and use a comparison operator to filter the search results.&lt;/p&gt;&lt;br/&gt;

&lt;h3&gt;Querying DynamoDB with the Partition Key&lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public PageIterable&amp;#x3C;Movie&amp;#x3E; findMovieByQuery(Long movieId) {
   Key key = Key.builder().partitionValue(movieId).build();
   QueryConditional queryConditional = QueryConditional.keyEqualTo(key);

   QueryEnhancedRequest queryEnhancedRequest = QueryEnhancedRequest.builder()
     .queryConditional(queryConditional)
     .build();

   PageIterable&amp;#x3C;Movie&amp;#x3E; moviePageIterable = dynamoDbTemplate.query(queryEnhancedRequest, Movie.class);
   return  moviePageIterable;
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;code&gt;QueryConditional&lt;/code&gt; : Defines the parameters that determine which items are returned when querying DynamoDB tables or indexes with the Query operation. These parameters specify the key conditions and any additional filtering criteria.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022; &lt;code&gt;QueryEnhancedRequest&lt;/code&gt; : Specifies conditions for finding items in DynamoDB tables or indexes with the Query operation.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 public void findMovieByQueryUsingMovieId()
 {
     PageIterable&amp;#x3C;Movie&amp;#x3E; movieByQuery = movieService.findMovieByQuery(MOVIE_ID);
     if (Objects.nonNull(movieByQuery))
     {
         SdkIterable&amp;#x3C;Movie&amp;#x3E; items = movieByQuery.items();
         if (Objects.nonNull(items))
             items.forEach(System.out::println);
     }
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;Querying DynamoDB with the Partition Key and Sort key&lt;/h3&gt;

&lt;p&gt;Just like with the partition key, you can define the sort key for your DynamoDB query by setting it in a &lt;code&gt;Key&lt;/code&gt; object and passing that object to the &lt;code&gt;QueryConditional&lt;/code&gt; class.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public PageIterable&amp;#x3C;Movie&amp;#x3E; findMovieByQuery(Long movieId, String movieTitle) {
   Key key = Key.builder().partitionValue(movieId).sortValue(movieTitle).build();
   QueryConditional queryConditional = QueryConditional.keyEqualTo(key);

   QueryEnhancedRequest queryEnhancedRequest = QueryEnhancedRequest.builder()
     .queryConditional(queryConditional).build();

   PageIterable&amp;#x3C;Movie&amp;#x3E; moviePageIterable = dynamoDbTemplate.query(queryEnhancedRequest, Movie.class);
   return  moviePageIterable;
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;DynamoDB Query Power: Partition Keys and Filter Expressions&lt;/h3&gt;

&lt;p&gt;While partition and sort keys are powerful for efficient queries, DynamoDB also allows you to search by other attributes when needed.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Many situations require querying DynamoDB based on attributes beyond the partition and sort keys. These queries leverage filter expressions, similar to how Scan operations utilize them. Filter expressions refine the results of a Query operation after the initial search using keys.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public PageIterable&amp;#x3C;Movie&amp;#x3E; findMovieByQuery(Long movieId, Double rating) {

   Key key = Key.builder().partitionValue(movieId).build();
   QueryConditional queryConditional = QueryConditional.keyEqualTo(key);

   Expression expression = Expression.builder()
     .expression(&amp;#x22;rating &amp;#x3E;= :rating_value&amp;#x22;)
     .putExpressionValue(&amp;#x22;:rating_value&amp;#x22;, AttributeValue.fromN(rating.toString()))
     .build();

   QueryEnhancedRequest queryEnhancedRequest = QueryEnhancedRequest.builder()
     .queryConditional(queryConditional) // query-condition with partition-key
     .filterExpression(expression) // filter-expression
     .build();

   PageIterable&amp;#x3C;Movie&amp;#x3E; moviePageIterable = dynamoDbTemplate.query(queryEnhancedRequest, Movie.class);
   return moviePageIterable;
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;h3&gt;Streamlining Results: Optimizing Data Retrieval with Projection Expressions&lt;/h3&gt;

&lt;p&gt;For situations where you only need a subset of data, DynamoDB offers projection expressions. These allow you to fetch only the relevant attributes from the table, reducing data transfer and improving performance.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;In the example below, we'll demonstrate how projection expressions work. We're only interested in retrieving two specific attributes: &lt;b&gt;movie_id&lt;/b&gt; and &lt;b&gt;movie_title&lt;/b&gt;.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Similarly, in the following example, I demonstrate how we may use both filter expression and projection expressions.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public PageIterable&amp;#x3C;Movie&amp;#x3E; findMovieTitle(String genreContain, Long movieId) {

   // it&amp;#x27;s mandatory to use the key with the filter expression
   Key key = Key.builder().partitionValue(movieId).build();
   QueryConditional queryConditional = QueryConditional.keyEqualTo(key);

   // filter expression, finding only those movie which genre&amp;#x27;s contain genreContain
   Expression expression = Expression.builder()
     .expression(&amp;#x22;contains(genre, :genre_contain_value)&amp;#x22;)
     .putExpressionValue(&amp;#x22;:genre_contain_value&amp;#x22;, AttributeValue.fromS(genreContain))
     .build();

   // Selecting only movie_id and movie title attributes only.
   List&amp;#x3C;NestedAttributeName&amp;#x3E; nestedAttributeNameList = new ArrayList&amp;#x3C;&amp;#x3E;();

   nestedAttributeNameList.add(NestedAttributeName.builder()
     .elements(&amp;#x22;movie_id&amp;#x22;)
     .build());

   nestedAttributeNameList.add(NestedAttributeName.builder()
     .elements(&amp;#x22;movie_title&amp;#x22;)
     .build());

   QueryEnhancedRequest queryEnhancedRequest = QueryEnhancedRequest.builder()
     .queryConditional(queryConditional)
     .filterExpression(expression) // filter-expression
     .addNestedAttributesToProject(nestedAttributeNameList) // projection-expression
     .build();

   PageIterable&amp;#x3C;Movie&amp;#x3E; moviePageIterable = dynamoDbTemplate.query(queryEnhancedRequest, Movie.class);
   return moviePageIterable;
 }&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;


&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Spring Cloud AWS provides a powerful and convenient way to integrate DynamoDB with your Spring Boot applications. By leveraging the &lt;code&gt;Query&lt;/code&gt; and &lt;code&gt;Scan&lt;/code&gt; operations, you can efficiently retrieve data based on specific criteria or scan the entire table as needed.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;We've explored using partition and sort keys for targeted queries, filter expressions for narrowing down results based on additional attributes, and projection expressions for optimizing data retrieval.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;With this knowledge, you can unlock the full potential of DynamoDB within your Spring Boot projects, ensuring efficient data access and streamlined application performance.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Optimize your DynamoDB interactions with BatchWriteItem and BatchGetItem, See how: &lt;a href="https://www.learnjavaskills.in/2024/08/dynamodb-batchwriteitem-and-batchgetitem-operations.html"&gt;(getButton) #text=(How to Use AWS DynamoDB BatchWriteItem and BatchGetItem in Java Spring Boot Applications) #icon=(link) #color=(#35a576)&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-dynamodb" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;
</content><link href="https://www.learnjavaskills.in/feeds/3648753781869824952/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/05/dynamodb-query-and-scan-operations.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/3648753781869824952" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/3648753781869824952" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/05/dynamodb-query-and-scan-operations.html" rel="alternate" title="Mastering DynamoDB Data Retrieval: Advanced Scan and Query Operations with Spring Boot and Spring Cloud AWS | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyo529jP_FwbL-zkHdNraIXNvZf7YtoOK2F4kD6xnocdgZ6M2L3h9w6a09UfAnh6lQRKNjYTkOXZBgWtZ5GbrAi_OeBCZKlYMDPwbOd3GVtM4RvrEd7fmKT0fzYyVsdUP0AKO2B1aDaEhPgTuBqkhPokK_qkFz9cDpYJn0l3JOtqKVcQ7nICliJaJjeLjx/s72-c/thumbnail.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-8737576808837226492</id><published>2024-04-30T14:03:00.007+05:30</published><updated>2024-05-11T20:34:22.566+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">Spring Boot, DynamoDB, and Spring Cloud AWS: A Step-by-Step Tutorial | Learn Java Skills</title><content type="html">&lt;p&gt;Building high-performance and scalable applications often requires a powerful database solution.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;If you're working with a Java Spring project and considering Amazon's robust NoSQL service, DynamoDB, this article is for you! We'll guide you through a seamless integration process using the &lt;b&gt;Spring Cloud AWS&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;By following this tutorial, you'll gain the knowledge and tools to leverage DynamoDB's flexibility and speed within your Spring application, taking your project's data storage capabilities to the next level.&lt;/p&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-dynamodb" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1gLgE7PDW8L8GB8R90XKvrEKMohkTf3HdpgzyjjtED_hdxn07drfYi9H76VYZfCGs41KpJ0Up5sfXAhzyZSRUvWcPMkkntyddl4wFy2YITq2qvq2wWVjbhCInt_6V21DPgDn0_r7enAt5AOvJunzOZWSuVVndoxDRYkwCNElGX5f7gVe-luc0JNotjIow/s1600/test_thumbnail.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="thumbnail image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1gLgE7PDW8L8GB8R90XKvrEKMohkTf3HdpgzyjjtED_hdxn07drfYi9H76VYZfCGs41KpJ0Up5sfXAhzyZSRUvWcPMkkntyddl4wFy2YITq2qvq2wWVjbhCInt_6V21DPgDn0_r7enAt5AOvJunzOZWSuVVndoxDRYkwCNElGX5f7gVe-luc0JNotjIow/s1600/test_thumbnail.png"/&gt;&lt;/a&gt;&lt;/div&gt; &lt;br/&gt;

&lt;strike&gt;toc&lt;/strike&gt; &lt;br/&gt;

&lt;h2&gt;Dive into DynamoDB: A Scalable NoSQL Powerhouse for Modern Applications&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;DynamoDB is a NoSQL, key-value database service offered by Amazon Web Services (AWS). Unlike relational databases that rely on predefined schemas, DynamoDB offers a flexible data model that scales seamlessly to accommodate massive datasets and surging traffic&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;This makes it ideal for applications with unpredictable workloads or those requiring ultra-low latency for data access.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Imagine building a mobile app with millions of users – DynamoDB can effortlessly handle the surge in data traffic, ensuring a smooth and responsive experience for everyone.&lt;/p&gt;&lt;br/&gt;

&lt;h2&gt;Creating a DynamoDB Table with the AWS CLI&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Before you can interact with DynamoDB from your Spring Cloud AWS application, you'll need to have a table already set up in your DynamoDB database.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Make sure you have the AWS CLI installed and configured with your AWS access key ID and secret access key. This allows the CLI to interact with your AWS resources, including DynamoDB. You can find instructions for configuration in the &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-quickstart.html" target="_blank" rel="nofollow"&gt;AWS documentation&lt;/a&gt;&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class="Bash"&gt; aws dynamodb create-table --table-name movie \
    --attribute-definitions AttributeName=movie_id,AttributeType=N AttributeName=movie_title,AttributeType=S \
    --key-schema AttributeName=movie_id,KeyType=HASH AttributeName=movie_title,KeyType=RANGE \
    --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;Once you executed the above script, you should see your table details in JSON format in the response, as seen below.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "json"&gt;{
    &amp;quot;TableDescription&amp;quot;: {
        &amp;quot;AttributeDefinitions&amp;quot;: [
            {
                &amp;quot;AttributeName&amp;quot;: &amp;quot;movie_id&amp;quot;,
                &amp;quot;AttributeType&amp;quot;: &amp;quot;N&amp;quot;
            },
            {
                &amp;quot;AttributeName&amp;quot;: &amp;quot;movie_title&amp;quot;,
                &amp;quot;AttributeType&amp;quot;: &amp;quot;S&amp;quot;
            }
        ],
        &amp;quot;TableName&amp;quot;: &amp;quot;movie&amp;quot;,
        &amp;quot;KeySchema&amp;quot;: [
            {
                &amp;quot;AttributeName&amp;quot;: &amp;quot;movie_id&amp;quot;,
                &amp;quot;KeyType&amp;quot;: &amp;quot;HASH&amp;quot;
            },
            {
                &amp;quot;AttributeName&amp;quot;: &amp;quot;movie_title&amp;quot;,
                &amp;quot;KeyType&amp;quot;: &amp;quot;RANGE&amp;quot;
            }
        ],
        &amp;quot;TableStatus&amp;quot;: &amp;quot;CREATING&amp;quot;,
        &amp;quot;CreationDateTime&amp;quot;: &amp;quot;2024-04-26T10:33:15.733000+00:00&amp;quot;,
        &amp;quot;ProvisionedThroughput&amp;quot;: {
            &amp;quot;NumberOfDecreasesToday&amp;quot;: 0,
            &amp;quot;ReadCapacityUnits&amp;quot;: 1,
            &amp;quot;WriteCapacityUnits&amp;quot;: 1
        },
        &amp;quot;TableSizeBytes&amp;quot;: 0,
        &amp;quot;ItemCount&amp;quot;: 0,
        &amp;quot;TableArn&amp;quot;: &amp;quot;arn:aws:dynamodb:us-east-1:581907371749:table/movie&amp;quot;,
        &amp;quot;TableId&amp;quot;: &amp;quot;ef4ae555-0d45-4ba5-a846-d78c6098d765&amp;quot;,
        &amp;quot;DeletionProtectionEnabled&amp;quot;: false
    }
}&lt;/code&gt;&lt;/pre&gt; 


&lt;blockquote&gt;Maximum number of tables per account and region.&lt;br/&gt;
Any AWS account has an initial quota of 2,500 tables per AWS Region.&lt;br/&gt;&lt;br/&gt;
  
If you require more than 2,500 tables for a single account, please contact the Amazon Web Services (AWS) support team to discuss an increase to a maximum of 10,000 tables. For more than 10,000 tables, the recommended best practice is to create numerous accounts, each capable of serving up to 10,000 tables.(alert-passed)&lt;/blockquote&gt;


&lt;h2&gt;Adding the Spring Cloud AWS DynamoDB dependency&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Spring Cloud AWS provides a starter dependency to simplify integrating with DynamoDB.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class="gradle"&gt; ext {
    springCloudAwsVersion = '3.0.0'
 }

 dependencies {
    // spring cloud aws BOM(Bill of materials)
    implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:${springCloudAwsVersion}")
    // dynamoDB
    implementation 'io.awspring.cloud:spring-cloud-aws-starter-dynamodb'
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Configuring DynamoDB with Spring Boot and Spring Cloud AWS (application.properties)&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;This simple configuration guide explains how to integrate Amazon DynamoDB into your Spring Boot application with Spring Cloud AWS. Details on credentials, region, and connection properties will be included in the &lt;code&gt;application.properties&lt;/code&gt; file.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class="properties"&gt; # DynamoDB connection
 spring.cloud.aws.credentials.access-key=AWS_ACCESS_KEY
 spring.cloud.aws.credentials.secret-key=AWS_SECRET_KEY
 # Choose your region according to your table. Because I have a DynamoDB table in the US-East-1 area, I've set the endpoint and region.
 spring.cloud.aws.region.static=us-east-1 
 spring.cloud.aws.endpoint=https://dynamodb.us-east-1.amazonaws.com&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Defining DynamoDB Documents (Model/Entity)&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;This guide dives into crafting well-structured documents (data models) for your &lt;b&gt;'Movies'&lt;/b&gt; table in DynamoDB.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;It clarifies the concept of DynamoDB documents (JSON data structures) and provides best practices for designing them to efficiently store and retrieve &lt;b&gt;movie&lt;/b&gt; data within your application.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class="java"&gt;package in.learnjavaskills.springcloudawsdynamodb.document;

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.util.List;
import java.util.Map;
import java.util.Set;

@DynamoDbBean
public class Movie
{
    private Long movieId;
    private String movieTitle;
    private Map&amp;lt;String, List&amp;lt;String&amp;gt;&amp;gt; directors;
    private Set&amp;lt;String&amp;gt; characters;
    private Genres genre;
    private Boolean baseOnBook;
    private Double rating;

    public Movie()
    {
    }

    public Movie(Long movieId, String movieTitle, Map&amp;lt;String, List&amp;lt;String&amp;gt;&amp;gt; directors, Set&amp;lt;String&amp;gt; characters, Genres genre, Boolean baseOnBook, Double rating)
    {
        this.movieId = movieId;
        this.movieTitle = movieTitle;
        this.directors = directors;
        this.characters = characters;
        this.genre = genre;
        this.baseOnBook = baseOnBook;
        this.rating = rating;
    }

    @DynamoDbPartitionKey
    @DynamoDbAttribute(value = &amp;quot;movie_id&amp;quot;)
    public Long getMovieId()
    {
        return movieId;
    }

    public void setMovieId(Long movieId)
    {
        this.movieId = movieId;
    }

    @DynamoDbSortKey
    @DynamoDbAttribute(value = &amp;quot;movie_title&amp;quot;)
    public String getMovieTitle()
    {
        return movieTitle;
    }

    public void setMovieTitle(String movieTitle)
    {
        this.movieTitle = movieTitle;
    }

    @DynamoDbAttribute(value = &amp;quot;directors&amp;quot;)
    public Map&amp;lt;String, List&amp;lt;String&amp;gt;&amp;gt; getDirectors()
    {
        return directors;
    }

    public void setDirectors(Map&amp;lt;String, List&amp;lt;String&amp;gt;&amp;gt; directors)
    {
        this.directors = directors;
    }

    public Set&amp;lt;String&amp;gt; getCharacters()
    {
        return characters;
    }

    public void setCharacters(Set&amp;lt;String&amp;gt; characters)
    {
        this.characters = characters;
    }

    public Genres getGenre()
    {
        return genre;
    }

    public void setGenre(Genres genre)
    {
        this.genre = genre;
    }

    public Boolean getBaseOnBook()
    {
        return baseOnBook;
    }

    public void setBaseOnBook(Boolean baseOnBook)
    {
        this.baseOnBook = baseOnBook;
    }

    public Double getRating()
    {
        return rating;
    }

    public void setRating(Double rating)
    {
        this.rating = rating;
    }

    @Override
    public String toString()
    {
        return &amp;quot;Movie{&amp;quot; + &amp;quot;movieId=&amp;quot; + movieId + &amp;quot;, movieTitle=&amp;#39;&amp;quot; + movieTitle + &amp;#39;\&amp;#39;&amp;#39; + &amp;quot;, directors=&amp;quot; + directors + &amp;quot;, characters=&amp;quot; + characters + &amp;quot;, genre=&amp;quot; + genre + &amp;quot;, baseOnBook=&amp;quot; + baseOnBook + &amp;quot;, rating=&amp;quot; + rating + &amp;#39;}&amp;#39;;
    }
}&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;Introducing &lt;code&gt;@DynamoDbBean&lt;/code&gt;: Mapping Your Model to DynamoDB Documents&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;@DynamoDbBean&lt;/code&gt; annotation is a cornerstone of Spring Cloud AWS for interacting with Amazon DynamoDB.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;It acts as a bridge between your application's model classes and DynamoDB documents, allowing you to seamlessly map your data structures to the NoSQL database format.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;Key Attributes: @DynamoDbPartitionKey and @DynamoDbSortKey&lt;/h3&gt;

&lt;p&gt;Within a DynamoDB table, data is organized using primary keys. Spring Cloud AWS provides annotations to define these keys within your model classes:&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&amp;#x2022 &lt;code&gt;@DynamoDbPartitionKey&lt;/code&gt;: This annotation marks a property in your model class as the partition key. The partition key is the primary way DynamoDB partitions your data and efficiently retrieves items. It's crucial to choose an attribute with high cardinality (frequent unique values) for optimal performance.&lt;/p&gt;

&lt;blockquote&gt;Partition key length&lt;br/&gt;The minimum length of a partition key value is 1 byte. The maximum length is 2048 bytes.(alert-success)&lt;/blockquote&gt;

&lt;p&gt;&amp;#x2022 &lt;code&gt;@DynamoDbSortKey&lt;/code&gt;: This annotation identifies a property as the sort key.  The sort key further refines how DynamoDB retrieves items within a partition. It's often used for efficient range queries on frequently accessed data sets within a partition.&lt;/p&gt;

&lt;blockquote&gt;Sort key length&lt;br/&gt;The minimum length of a sort key value is 1 byte. The maximum length is 1024 bytes.(alert-success)&lt;/blockquote&gt;

&lt;h3&gt;Mapping Model Properties: @DynamoDbAttribute&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;@DynamoDbAttribute&lt;/code&gt; annotation plays a vital role in Spring Cloud AWS for DynamoDB. It signifies that a property in your model class corresponds to an attribute within a DynamoDB document. Here's a breakdown of its functionality: &lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&amp;#x2022 &lt;b&gt;Marks Properties&lt;/b&gt;: It explicitly tells Spring Cloud AWS to map the annotated property to a DynamoDB attribute.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022 &lt;b&gt;Optional (Sometimes)&lt;/b&gt;: By default, if the property name in your model class matches the DynamoDB attribute name, this annotation is not strictly required. As evident in the movie mode class, I have purposefully chosen not to use this annotation for a few of the properties. Spring Cloud AWS will match the DynamoDB attribute with the movie class property name.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022 &lt;b&gt;Custom Attribute Names&lt;/b&gt;: If the property name differs from the desired DynamoDB attribute name, you can specify the attribute name using the &lt;code&gt;value&lt;/code&gt; parameter within the annotation.&lt;/p&gt;

&lt;blockquote&gt;Attribute names&lt;br/&gt;In general, an attribute name must be at least one character long, but no greater than 64 KB long.(alert-success)&lt;/blockquote&gt;

&lt;h2&gt;Performing CRUD Operations on DynamoDB with Spring Cloud AWS&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Let's explore at the Create, Read, Update, and Delete (CRUD) operations on the DynamoDB table we created earlier, i.e., the movie, using Spring Cloud AWS.&lt;/p&gt;&lt;br/&gt; 

&lt;h3&gt;The DynamoDBTemplate: Your Interface for CRUD Operations&lt;/h3&gt;

&lt;p&gt;The starter automatically configures and registers a &lt;code&gt;DynamoDbOperations&lt;/code&gt; bean, which provides higher-level abstractions for working with &lt;b&gt;DynamoDB&lt;/b&gt;. &lt;code&gt;DynamoDbTemplate&lt;/code&gt;, a default &lt;b&gt;DynamoDbOperations&lt;/b&gt; implementation, is built on top of &lt;code&gt;DynamoDbEnhancedClient&lt;/code&gt; and uses annotations provided by AWS.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;DynamoDbTemplate allow you to perform CRUD operations (Create, Read, Update, Delete) on your DynamoDB tables in a more convenient and Spring-friendly manner and It may be found in the &lt;code&gt;io.awspring.cloud.dynamodb.DynamoDbTemplate&lt;/code&gt; package.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;Persisting Movie Data: Saving Movies with DynamoDBTemplate&lt;/h3&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIacImfuC_ANSOLiUBzN99ls7nIw0mzhZRTtZCmTt0SRiYNvx2o6LISPR5A0tEuzX7_LpzmSlNgkW7-X_Q4-q0jhaS33PLVhMubK8ocr9gfePGJQ4aeoG5cwNsxNAnhHpJC-oIdnFMsy8_zQvmKN3YrPeeTq_hjadjGBBg2BEQFCWdN5TV4QkHgoWeMV4v/s1600/insert-thumbnail.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="inserting data into dynamodb thumbnail image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIacImfuC_ANSOLiUBzN99ls7nIw0mzhZRTtZCmTt0SRiYNvx2o6LISPR5A0tEuzX7_LpzmSlNgkW7-X_Q4-q0jhaS33PLVhMubK8ocr9gfePGJQ4aeoG5cwNsxNAnhHpJC-oIdnFMsy8_zQvmKN3YrPeeTq_hjadjGBBg2BEQFCWdN5TV4QkHgoWeMV4v/s1600/insert-thumbnail.png"/&gt;&lt;/a&gt;&lt;/div&gt; &lt;br/&gt;

&lt;p&gt;This section explores how to leverage the &lt;code&gt;DynamoDbTemplate&lt;/code&gt; class to seamlessly save movie data within your DynamoDB 'Movies' table. Notably, the &lt;code&gt;save&lt;/code&gt; method within &lt;b&gt;DynamoDbTemplate&lt;/b&gt; serves as the primary mechanism for persisting your movie information as documents in the DynamoDb database.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "Java"&gt; public Long addMovie(Movie movie) {
    if (Objects.isNull(movie))
        throw new DynamoDbDataException(&amp;quot;Movie must be non null&amp;quot;);

    Movie savedMovie = dynamoDbTemplate.save(movie);
    if (Objects.nonNull(savedMovie) &amp;amp;&amp;amp; Objects.nonNull(savedMovie.getMovieId()))
        return savedMovie.getMovieId();
    throw new DynamoDbDataException(&amp;quot;Unsaved movie, Please try again.&amp;quot;);
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "Java"&gt; public static final String HARRY_POTTER_AND_THE_DEATHLY_HALLOWS_PART_1 = &amp;quot;Harry Potter and the Deathly Hallows: Part 1&amp;quot;;
 public static final long MOVIE_ID = 101L;
 @Autowired private MovieService movieService;

 @Test
 void saveMovie() {
    Map&amp;lt;String, List&amp;lt;String&amp;gt;&amp;gt; directors = new HashMap&amp;lt;&amp;gt;();
    List&amp;lt;String&amp;gt; directorsName = new ArrayList&amp;lt;&amp;gt;();
    directorsName.add(&amp;quot;David Yates&amp;quot;);
    directors.put(&amp;quot;Dir1&amp;quot;, directorsName);

    Set&amp;lt;String&amp;gt; characters = new HashSet&amp;lt;&amp;gt;();
    characters.add(&amp;quot;Harry Potter&amp;quot;);
    characters.add(&amp;quot;Hermione Granger&amp;quot;);
    characters.add(&amp;quot;Ron Weasley&amp;quot;);
    characters.add(&amp;quot;Draco Malfoy&amp;quot;);

    Movie movie = new Movie(MOVIE_ID, HARRY_POTTER_AND_THE_DEATHLY_HALLOWS_PART_1,
		directors, characters, Genres.DRAMA, true, 3.9);

    Long movieId = movieService.addMovie(movie);
    Assertions.assertThat(movieId).isEqualTo(movie.getMovieId());
 }&lt;/code&gt;&lt;/pre&gt; 

&lt;blockquote&gt;DynamoDB's maximum item size is 400 KB, which includes both attribute name binary length (UTF-8 length) and attribute value lengths (again, binary length). The attribute name counts toward the size limit. &lt;br/&gt;
  
For example, take an item with two attributes: "movie-name" with the value "Harry Potter and the Philosopher's Stone" and "release-date" with the value "2001". The item's entire size is 67 bytes. (alert-passed)&lt;/blockquote&gt;

&lt;h3&gt;Retrieving Movie Information: Reading Data with DynamoDBTemplate&lt;/h3&gt;
&lt;hr&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg50H9Z76hU11QTpCuh8cr02gGd0Y_2vQk0qmvubwyWtq3tlYeKQUIku9lcw-sN5QjJakXLPzPcth3aTbtkOULAq1v2W3c8J71fuXtRERv3NSeG7HAusPfNw7jXJkiQh2Lty3zoNj__EURGPRY8M0sMqGq0sbeb4lJAdDjajKBy0uomKq9YCIQpcrQEzzva/s1600/find-thumbnail.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="searcing data in dynamodb thumbnail image" border="0" data-original-height="736" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg50H9Z76hU11QTpCuh8cr02gGd0Y_2vQk0qmvubwyWtq3tlYeKQUIku9lcw-sN5QjJakXLPzPcth3aTbtkOULAq1v2W3c8J71fuXtRERv3NSeG7HAusPfNw7jXJkiQh2Lty3zoNj__EURGPRY8M0sMqGq0sbeb4lJAdDjajKBy0uomKq9YCIQpcrQEzzva/s1600/find-thumbnail.png"/&gt;&lt;/a&gt;&lt;/div&gt; &lt;br/&gt;

&lt;p&gt;This section explores how to efficiently retrieve movie data from your DynamoDB 'Movies' table using the &lt;code&gt;DynamoDbTemplate&lt;/code&gt; class.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;A core method for retrieving data is the &lt;code&gt;load&lt;/code&gt; method. It takes two crucial parameters:&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&amp;#x2022 &lt;b&gt;Class&lt;/b&gt;: This specifies the class that represents your movie data model (the class annotated with &lt;b&gt;@DynamoDbBean&lt;/b&gt;)&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;&amp;#x2022 &lt;b&gt;Key&lt;/b&gt;: This parameter is fundamental for pinpointing the specific movie entry you want to fetch. The key should correspond to the primary key defined in your model class using &lt;code&gt;@DynamoDbPartitionKey&lt;/code&gt; and optionally &lt;code&gt;@DynamoDbSortKey&lt;/code&gt; annotations. By providing the appropriate key values, load efficiently retrieves the corresponding movie document from DynamoDB.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class="java"&gt; public Optional&amp;lt;Movie&amp;gt; findMovie(Long movieId, String movieTitle) {
    Key key = Key.builder()
    	.partitionValue(movieId)
        .sortValue(movieTitle)
        .build();
    Movie movie = dynamoDbTemplate.load(key, Movie.class);
    return Optional.ofNullable(movie);
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class="java"&gt; @Test
 public void findMovie() {
    Optional&amp;lt;Movie&amp;gt; movie = movieService.findMovie(MOVIE_ID, HARRY_POTTER_AND_THE_DEATHLY_HALLOWS_PART_1);
    Assertions.assertThat(movie).isPresent();
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;Removing Movies: Deleting Items with DynamoDBTemplate&lt;/h3&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpGtgk2XCADl6U-z9srzAAi7l52lqaiccA-rO_Ztr8cgDO6m0aAxvoi0ErJC7TwYNztQb5KE-4pJXtATjLimcX-m6KAeyk7SCAmpiN7Krk-l8097TxE2Z7lNerj31KMo2b_qzDYwDkfUGCTvDtqpusEK8V6ixGIJheYv7wISkMbFfx6Fs6MPM6PWVOp6J4/s1600/delete-thumbnail.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Deleting items from dynamoDB thumbnail image" border="0" data-original-height="817" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpGtgk2XCADl6U-z9srzAAi7l52lqaiccA-rO_Ztr8cgDO6m0aAxvoi0ErJC7TwYNztQb5KE-4pJXtATjLimcX-m6KAeyk7SCAmpiN7Krk-l8097TxE2Z7lNerj31KMo2b_qzDYwDkfUGCTvDtqpusEK8V6ixGIJheYv7wISkMbFfx6Fs6MPM6PWVOp6J4/s1600/delete-thumbnail.png"/&gt;&lt;/a&gt;&lt;/div&gt; &lt;br/&gt;

&lt;p&gt;This section tackles deleting movie entries from your DynamoDB 'Movies' table using the &lt;b&gt;DynamoDbTemplate&lt;/b&gt; class.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Just like the &lt;b&gt;load()&lt;/b&gt; method, the &lt;b&gt;delete()&lt;/b&gt; method also takes two objects as input, i.e., the &lt;b&gt;key&lt;/b&gt; and the instance of the &lt;b&gt;model class&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; void deleteMovie(Long movieId, String movieTitle) {
    Key key = Key.builder()
    	.partitionValue(movieId)
        .sortValue(movieTitle)
        .build();
    dynamoDbTemplate.delete(key, Movie.class);
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;pre&gt;&lt;code class="java"&gt; @Test
 public void deleteMovie() {
    movieService.deleteMovie(MOVIE_ID, HARRY_POTTER_AND_THE_DEATHLY_HALLOWS_PART_1);
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;You may alternatively simply delete entries from the DynamoDB table by calling the overloaded delete method and accepting the data model, as seen in the example below.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class="java"&gt; public void deleteMovie(Movie movie) {
     dynamoDbTemplate.delete(movie);
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;h3&gt;Modifying Movies: Updating Data with DynamoDBTemplate&lt;/h3&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrNO5394EY_M2hpY_pu8oyDC2A6Me3CLz7JKVpEedeSjfdNqKnVkrdzzoJNTBlAVRXU1myOcPmTnhwFju8EE5G_ppOzq0p9AOgLWLXiTuEWF1_O78cF3Q2W-mjnQKVRPRWitA3GwYzNKV9rIMoWLQmoUvIY7AlTq4le-qSTSRwg8CbG-VAed0H9ogf5Nob/s1600/update.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="updating items from dynamodb thumbnail image" border="0" data-original-height="977" data-original-width="1912" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrNO5394EY_M2hpY_pu8oyDC2A6Me3CLz7JKVpEedeSjfdNqKnVkrdzzoJNTBlAVRXU1myOcPmTnhwFju8EE5G_ppOzq0p9AOgLWLXiTuEWF1_O78cF3Q2W-mjnQKVRPRWitA3GwYzNKV9rIMoWLQmoUvIY7AlTq4le-qSTSRwg8CbG-VAed0H9ogf5Nob/s1600/update.png"/&gt;&lt;/a&gt;&lt;/div&gt; &lt;br/&gt;

&lt;p&gt;This section delves into updating existing movie entries within your DynamoDB 'Movies' table using the &lt;b&gt;DynamoDbTemplate&lt;/b&gt; class. We'll explore how to leverage the update method of &lt;b&gt;DynamoDbTemplate&lt;/b&gt; to make targeted changes to your movie data, ensuring your information remains accurate and up-to-date.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The &lt;code&gt;update&lt;/code&gt; method is the primary mechanism for updating data in DynamoDB. It takes a single argument:&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&amp;#x2022 &lt;b&gt;Your Model Class Instance&lt;/b&gt;: You pass an instance of your movie data model class (annotated with @DynamoDbBean). The update method recognizes the changes made to the object's properties and translates them into corresponding updates within the DynamoDB document associated with the movie's primary key. This approach simplifies the update process, as you only need to modify the relevant fields in your model object.&lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; public Long updateMovie(Movie movie) { 
    Movie updatedMovie = dynamoDbTemplate.update(movie);
    if (Objects.nonNull(updatedMovie))
      return updatedMovie.getMovieId();
    return 0L;
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; @Test
 public void updateMovie() {
    Map&amp;lt;String, List&amp;lt;String&amp;gt;&amp;gt; directors = new HashMap&amp;lt;&amp;gt;();
    List&amp;lt;String&amp;gt; directorsName = new ArrayList&amp;lt;&amp;gt;();
    directorsName.add(&amp;quot;David Yates&amp;quot;);
    directors.put(&amp;quot;Dir1&amp;quot;, directorsName);

    Set&amp;lt;String&amp;gt; characters = new HashSet&amp;lt;&amp;gt;();
    characters.add(&amp;quot;Harry Potter&amp;quot;);
    characters.add(&amp;quot;Hermione Granger&amp;quot;);
    characters.add(&amp;quot;Ron Weasley&amp;quot;);
    characters.add(&amp;quot;Draco Malfoy&amp;quot;);

    Movie movie = new Movie(MOVIE_ID, HARRY_POTTER_AND_THE_DEATHLY_HALLOWS_PART_1,
        directors, characters, Genres.DRAMA, true, 4.7);

    Long movieId = movieService.updateMovie(movie);
    Assertions.assertThat(movieId).isEqualTo(MOVIE_ID);
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;This article has explored performing &lt;b&gt;CRUD&lt;/b&gt; operations (Create, Read, Update, Delete) on your DynamoDB 'Movies' table using Spring Cloud AWS and the &lt;code&gt;DynamoDbTemplate&lt;/code&gt; class. We've equipped you with the tools to effectively manage your movie data within the DnamoDb database.&lt;/p&gt;

&lt;p&gt;The complete code for this project is available on my GitHub repository &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-aws-dynamodb" target="_blank" rel="nofollow"&gt;(getButton) #text=(GitHub) #icon=(share) #color=(#000000)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a deep dive into scan and query operations, this blog is a great resource: &lt;a href="https://www.learnjavaskills.in/2024/05/dynamodb-query-and-scan-operations.html"&gt;(getButton) #text=(Mastering DynamoDB Data Retrieval: Advanced Scan and Query Operations) #icon=(link) #color=(#35a576)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;




</content><link href="https://www.learnjavaskills.in/feeds/8737576808837226492/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/04/spring-cloud-aws-dynamodb.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/8737576808837226492" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/8737576808837226492" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2024/04/spring-cloud-aws-dynamodb.html" rel="alternate" title="Spring Boot, DynamoDB, and Spring Cloud AWS: A Step-by-Step Tutorial | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1gLgE7PDW8L8GB8R90XKvrEKMohkTf3HdpgzyjjtED_hdxn07drfYi9H76VYZfCGs41KpJ0Up5sfXAhzyZSRUvWcPMkkntyddl4wFy2YITq2qvq2wWVjbhCInt_6V21DPgDn0_r7enAt5AOvJunzOZWSuVVndoxDRYkwCNElGX5f7gVe-luc0JNotjIow/s72-c/test_thumbnail.png" width="72"/><thr:total>0</thr:total><georss:featurename>Mumbai, Maharashtra, India</georss:featurename><georss:point>19.0759837 72.8776559</georss:point><georss:box>-23.273727530936288 2.5651558999999935 61.425694930936288 143.19015589999998</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-5210293520487903286</id><published>2024-03-03T15:16:00.000+05:30</published><updated>2024-03-03T15:16:22.759+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">How to create serverless function with spring cloud function, deploy into AWS Lambda and expose rest endpoint using AWS API Gateway | Learn Java Skills</title><content type="html">&lt;div&gt;
  &lt;p&gt;
    Now a days, serverless functions are gaining much more popularity because
    developers don't want to spend valuable time configuring the server
    themselves or maintaining the operating system patch update manually.
  &lt;/p&gt;
  &lt;br /&gt;

  &lt;p&gt;
    There are three main advantages to using the serverless function (Spring
    Cloud Function).
  &lt;/p&gt;
  &lt;br /&gt;
  &lt;ul&gt;
    &lt;li&gt;
      No efforts were required for us to setup servers, like software
      installation, before deploying them into production.
    &lt;/li&gt;
    &lt;br /&gt;
    &lt;li&gt;
      Maintenance of the server, like software patch updates, is eliminated.
    &lt;/li&gt;
    &lt;br /&gt;
    &lt;li&gt;
      Serverless functions are auto-scalable by nature if you deploy them in the
      cloud, such as AWS, GCP, or Azure.
    &lt;/li&gt;
    &lt;br /&gt;
  &lt;/ul&gt;

  &lt;p&gt;
    In this tutorial, you can expect to learn how to build your first serverless
    function using the Spring cloud function and deploy it into the cloud.
  &lt;/p&gt;
  &lt;br /&gt;

  &lt;p&gt;
    There are many cloud providers that offer serverless function deployment,
    such as Google (GCP), Azure, or Amazon AWS. In this tutorial, you can expect
    the end-to-end development of the spring cloud function and deployment into
    the AWS lambda.
  &lt;/p&gt;
  &lt;br /&gt;

  &lt;p&gt;
    We are not only deploying our cloud function into AWS, but we will also make
    sure that it is accessible via the Rest endpoint by configuring the AWS API
    Gateway with our AWS lambda.
  &lt;/p&gt;
&lt;/div&gt;

&lt;br/&gt;

&lt;strike&gt;toc&lt;/strike&gt;

&lt;br/&gt;


&lt;!-- Thumbnail image --&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcTTTL7U8TAoqQLe5dzWJifdPvgeTGs51-CTSs1tqFDPXoSqFcZIwWfPIiSQNl9Y2K7LcJq444w3hxY02SV-Qm6_z9EwOQzu7khpBCR4w5qrn6ZEP7WJJXhBREDkvR3Yd_LJ99Oquj9ZHIVt-n39ij2FWLIVtMel5P-9rk0yug68I3uJJcbZ8gxJGuCUbZ/s1600/serverless%20function%20logo%202.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="SERVERLESS FUNCTION WITH SPRING CLOUD FUNCTION | AWS LAMBDA | AWS API GATEWAY thumbnail image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcTTTL7U8TAoqQLe5dzWJifdPvgeTGs51-CTSs1tqFDPXoSqFcZIwWfPIiSQNl9Y2K7LcJq444w3hxY02SV-Qm6_z9EwOQzu7khpBCR4w5qrn6ZEP7WJJXhBREDkvR3Yd_LJ99Oquj9ZHIVt-n39ij2FWLIVtMel5P-9rk0yug68I3uJJcbZ8gxJGuCUbZ/s1600/serverless%20function%20logo%202.png"/&gt;&lt;/a&gt;&lt;/div&gt;



&lt;div&gt;
  &lt;h2&gt;This tutorial is divided into four sections, as follows:&lt;/h2&gt;
  &lt;hr&gt;
  &lt;br/&gt;
  &lt;ul&gt;
    &lt;li&gt;First, we will create a Spring cloud function and run it locally.&lt;/li&gt;
    &lt;br /&gt;
    &lt;li&gt;
      Second, in Spring Boot version 3, we are going to build a Spring Cloud function that should be compatible with AWS lambda function deployment.
    &lt;/li&gt;
    &lt;br /&gt;
    &lt;li&gt;
      We will learn how to trigger the AWS lambda function with the AWS API
      Gateway endpoint.
    &lt;/li&gt;
    &lt;br /&gt;
    &lt;li&gt;
      Fourth, we'll look at how we can configure this spring cloud function in Spring Boot version 2, as well as what adjustments we need to make to the handler setting in the AWS lambda function when compared to Spring Boot version 3.
    &lt;/li&gt; &lt;br/&gt; 
  &lt;/ul&gt;
  &lt;div&gt;
    &lt;div&gt;
      &lt;h2&gt;Spring Cloud Function in local&lt;/h2&gt;
      &lt;hr&gt;
      &lt;p&gt;
        In this section we will learn how to develope a spring cloud function
        and run function locally.
      &lt;/p&gt; &lt;br/&gt;

      &lt;h3&gt;Maven Dependency&lt;/h3&gt;

      &lt;p&gt;
        Thre are two main dependencies need to be added and they are as followed
      &lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;spring-cloud-starter-function-web&lt;/li&gt;
        &lt;li&gt;spring-cloud-dependencies&lt;/li&gt;
      &lt;/ul&gt;
      &lt;br /&gt;

      &lt;pre&gt;&lt;code class = "xml:brush"&gt;  &amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
 &amp;lt;project xmlns=&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot; xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;
   xsi:schemaLocation=&amp;quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&amp;quot;&amp;gt;
   &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
   &amp;lt;parent&amp;gt;
      &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;spring-boot-starter-parent&amp;lt;/artifactId&amp;gt;
      &amp;lt;version&amp;gt;3.1.3&amp;lt;/version&amp;gt;
      &amp;lt;relativePath/&amp;gt; &amp;lt;!-- lookup parent from repository --&amp;gt;
   &amp;lt;/parent&amp;gt;
   &amp;lt;groupId&amp;gt;in.learnjavaskills&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;spring-cloud-function-local&amp;lt;/artifactId&amp;gt;
   &amp;lt;version&amp;gt;0.0.1-SNAPSHOT&amp;lt;/version&amp;gt;
   &amp;lt;name&amp;gt;spring-cloud-function-local&amp;lt;/name&amp;gt;
   &amp;lt;description&amp;gt;Demo project for Spring Boot&amp;lt;/description&amp;gt;
   &amp;lt;properties&amp;gt;
      &amp;lt;java.version&amp;gt;17&amp;lt;/java.version&amp;gt;
      &amp;lt;spring-cloud.version&amp;gt;2022.0.4&amp;lt;/spring-cloud.version&amp;gt;
   &amp;lt;/properties&amp;gt;
   &amp;lt;dependencies&amp;gt;
      &amp;lt;!-- Spring Cloud Function  --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-cloud-starter-function-web&amp;lt;/artifactId&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-boot-starter-test&amp;lt;/artifactId&amp;gt;
         &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
   &amp;lt;/dependencies&amp;gt;
   &amp;lt;dependencyManagement&amp;gt;
      &amp;lt;dependencies&amp;gt;
         &amp;lt;!-- spring cloud dependencies --&amp;gt;
         &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-cloud-dependencies&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;${spring-cloud.version}&amp;lt;/version&amp;gt;
            &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
            &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
         &amp;lt;/dependency&amp;gt;
      &amp;lt;/dependencies&amp;gt;
   &amp;lt;/dependencyManagement&amp;gt;

   &amp;lt;build&amp;gt;
      &amp;lt;plugins&amp;gt;
         &amp;lt;plugin&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;
         &amp;lt;/plugin&amp;gt;
      &amp;lt;/plugins&amp;gt;
   &amp;lt;/build&amp;gt;

 &amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

      &lt;h3&gt;
        The Spring cloud function along with the functional interface
        introduction.
      &lt;/h3&gt;
      &lt;p&gt;
        Only one rest endpoint can be expose by using the Spring cloud function.
        You can configure many functional interfaces with the bean in your
        application, but only one should be accessible to the end user at a
        time.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;p&gt;
        The Spring Cloud function exposes the rest endpoint using three
        frequently utilized functional interfaces. This functional interface,
        which was introduced in Java 8 as part of the
        &lt;b&gt;java.util.function&lt;/b&gt; package, is as follows:
      &lt;/p&gt; &lt;br/&gt;

      &lt;h3&gt;Function Interface&lt;/h3&gt;

      &lt;p&gt;
        The Function interface has two arguments that we must declare when
        utilizing it: &lt;b&gt;T&lt;/b&gt; and &lt;b&gt;R&lt;/b&gt;. The &lt;b&gt;T&lt;/b&gt; parameter indicates
        the function's request type, while the &lt;b&gt;R&lt;/b&gt; parameter determines the
        function's return type.
      &lt;/p&gt;
      &lt;br /&gt;
      &lt;pre&gt;&lt;code class = "java:brush"&gt; @FunctionalInterface
 public interface Function&amp;lt;T, R&amp;gt; {
 }&lt;/code&gt;&lt;/pre&gt;
      &lt;br /&gt;

      &lt;p&gt;
        The abstract method in the Function interface that we must override when
        using the Function interface is the &lt;b&gt;apply()&lt;/b&gt; method.
      &lt;/p&gt;
      &lt;br /&gt;
      &lt;p&gt;
        The &lt;u&gt;apply()&lt;/u&gt; method expects to return the result with the same
        return data type that we defined when we declared the generic type in
        the function interface. It accepts one argument of the data type that we
        specified when we created the function interface.
      &lt;/p&gt;
      &lt;br /&gt;
      
      &lt;blockquote&gt;R apply(T t);&lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt;&lt;br/&gt;

      &lt;h3&gt;Consumer Interface&lt;/h3&gt;
      &lt;p&gt;
        The consumer interface, as the name suggests, is used to consume data
        and does not return any data. The only generic available in the user
        interface is &lt;b&gt;T&lt;/b&gt;.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;pre&gt;&lt;code class = "java:brush"&gt; @FunctionalInterface
 public interface Consumer&amp;lt;T&amp;gt; {
 } &lt;/code&gt;&lt;/pre&gt;
      &lt;br /&gt;

      &lt;p&gt;
        The consumer interface has one abstract method, &lt;b&gt;accept()&lt;/b&gt;. The
        accept method takes one parameter of type specified as the consumer
        interface's generic type.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;blockquote&gt;void accept(T t);&lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt; &lt;br/&gt;

      &lt;h3&gt;Supplier Interface&lt;/h3&gt;
      &lt;p&gt;
        When we wish to get some data without providing any arguments as input,
        we utilize the supplier interface. When using the supplier interface, we
        only need to decide on one generic type, &lt;b&gt;T&lt;/b&gt;, which specifies the
        function's return type.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;pre&gt;&lt;code class = "java:brush"&gt; @FunctionalInterface
 public interface Supplier&amp;lt;T&amp;gt; {
 } &lt;/code&gt;&lt;/pre&gt;
      &lt;br /&gt;

      &lt;p&gt;
        The Supplier interface has one abstruct function, &lt;b&gt;get()&lt;/b&gt;. The
        get() method must return data of the same generic T type that has been
        defined in the Suppier interface's generic type.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;blockquote&gt;T get();&lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt;
      &lt;br /&gt;

      &lt;h3&gt;Developing a Rest API using the Spring cloud function&lt;/h3&gt;

      &lt;p&gt;
        I'm developing an API that will be responsible for counting the amount
        of words in a given String. I've created one  java &lt;a href="https://www.learnjavaskills.in/2023/09/what-is-a-record-in-java.html"&gt;record&lt;/a&gt; (Response) to
        transmit the API response. First, let's make a Response &lt;a href="https://www.learnjavaskills.in/2023/09/what-is-a-record-in-java.html"&gt;record&lt;/a&gt;.
      &lt;/p&gt;

      &lt;p&gt;
        If you are using Java 8 or Java 11, you may substitute POJO for the java
        &lt;a href="https://www.learnjavaskills.in/2023/09/what-is-a-record-in-java.html"&gt;record&lt;/a&gt;.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;pre&gt;&lt;code class = "java:brush"&gt; package in.learnjavaskills.springcloudfunctionlocal;

 public record Response(int status, String message, Long wordCount)
 {}&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

      &lt;h3&gt;Create a @Bean to expose the Rest Endpoint.&lt;/h3&gt;
      &lt;p&gt;
        After we've finished developing the response record file, we can start
        working on a bean to expose the rest enpoint.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;pre&gt;&lt;code class = "java:brush"&gt; package in.learnjavaskills.springcloudfunctionlocal;

 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.annotation.Bean;

 import java.util.Objects;
 import java.util.function.Function;

 @SpringBootApplication
 public class SpringCloudFunctionLocalApplication
 {

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

   @Bean(name = &amp;quot;find-word-count&amp;quot;)
   public Function&amp;lt;String, Response&amp;gt; findWordCount()
   {
     return request -&amp;gt;
     {
       if (Objects.nonNull(request) &amp;amp;&amp;amp; Objects.nonNull(request) &amp;amp;&amp;amp; !request.isEmpty())
       {
         if (request.contains(&amp;quot; &amp;quot;))
         {
           long wordCount = request.split(&amp;quot; &amp;quot;).length;
           return new Response(200, &amp;quot;success&amp;quot;, wordCount);
         }
       }
       return new Response(409, &amp;quot;fail&amp;quot;, 0L);
     };
   }
 }
&lt;/code&gt; &lt;/pre&gt;

      &lt;h3&gt;Testing rest enpoind&lt;/h3&gt;

      &lt;p&gt;
        Let's put it to the test now. Use curl to execute the above enpoint.
      &lt;/p&gt;
      &lt;br /&gt;
      
      &lt;blockquote&gt;curl -H &amp;quot;Content-Type: application/json&amp;quot; localhost:8080/find-word-count -d &amp;quot;Learn Java Skills&amp;quot;&lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt;
      &lt;br /&gt;

      &lt;p&gt;The output is shown below.&lt;/p&gt;
      &lt;br /&gt;
      &lt;blockquote&gt;{&amp;quot;status&amp;quot;:200,&amp;quot;message&amp;quot;:&amp;quot;success&amp;quot;,&amp;quot;wordCount&amp;quot;:3} &lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt;
    &lt;/div&gt;

    &lt;br /&gt;
    
   
    

    &lt;!-- Spring cloud function in AWS Lambda in spring boot version 3 --&gt;
    &lt;div&gt;
      &lt;h2&gt;
        How do you write a Spring Cloud function in Spring Boot 3 and publish
        it to AWS Lambda?
      &lt;/h2&gt;
      &lt;hr&gt;
      
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4VlELCDLf_o4JOXeMibqbg7EN0DvVH7QnMafq0jO_airslsfShMUFV5lpGJVB_A3qGVkGy6piAi__QBoAWEudJPzF_M-8nJh8gLmAALJ5_gBiZH0XT1EJklolUbR7ccZQQdUKL7ixqKDENxtRK_oPBkGntPqnu2Yp6dUNtwCHLYJaKFcuwNHNX2f50yoz/s1600/archetech%20diagram.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="architecture diagram" border="0" data-original-height="332" data-original-width="692" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4VlELCDLf_o4JOXeMibqbg7EN0DvVH7QnMafq0jO_airslsfShMUFV5lpGJVB_A3qGVkGy6piAi__QBoAWEudJPzF_M-8nJh8gLmAALJ5_gBiZH0XT1EJklolUbR7ccZQQdUKL7ixqKDENxtRK_oPBkGntPqnu2Yp6dUNtwCHLYJaKFcuwNHNX2f50yoz/s1600/archetech%20diagram.png"/&gt;&lt;/a&gt;&lt;/div&gt;
     

      &lt;p&gt;
        Till, Now we are able to develop the spring cloud function, which we can
        also run on our local machine. But this function is not yet ready to
        deploy into AWS because we do need to update the dependencies and code
        to make it compatible with the AWS lambda function.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;p&gt;
        Let's develop a serverless function with the Spring cloud function and
        deploy it to AWS Lambda. This time, we'll write a method that will
        reverse the given string.
      &lt;/p&gt; &lt;br/&gt;

      &lt;h3&gt;AWS Lambda Dependencies&lt;/h3&gt; &lt;br/&gt;

      &lt;p&gt;
        The libraries listed below are necessary in our project to develop the
        serverless function (Spring Cloud Function) and deploy it to AWS Lambda.
      &lt;/p&gt; &lt;br/&gt;

      &lt;ul&gt;
        &lt;li&gt;spring-cloud-function-adapter-aws&lt;/li&gt;
        &lt;li&gt;aws-lambda-java-events&lt;/li&gt;
        &lt;li&gt;aws-lambda-java-core&lt;/li&gt;
        &lt;li&gt;spring-cloud-dependencies&lt;/li&gt;
      &lt;/ul&gt;

      &lt;br /&gt;

      &lt;h3&gt;pom.xml&lt;/h3&gt;

      &lt;pre&gt;&lt;code class = "xml:brush"&gt; &amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;project xmlns=&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot; xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;
  xsi:schemaLocation=&amp;quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&amp;quot;&amp;gt;
  &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
  
  &amp;lt;parent&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter-parent&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.1.3&amp;lt;/version&amp;gt;
    &amp;lt;relativePath/&amp;gt; &amp;lt;!-- lookup parent from repository --&amp;gt;
  &amp;lt;/parent&amp;gt;
  
  &amp;lt;groupId&amp;gt;in.learnjavaskills&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;spring-cloud-function-aws-lambda&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;0.0.1-SNAPSHOT&amp;lt;/version&amp;gt;
  &amp;lt;name&amp;gt;spring-cloud-function-aws-lambda&amp;lt;/name&amp;gt;
  &amp;lt;description&amp;gt;Demo project for Spring Boot&amp;lt;/description&amp;gt;
  
  &amp;lt;properties&amp;gt;
    &amp;lt;java.version&amp;gt;17&amp;lt;/java.version&amp;gt;
    &amp;lt;spring-cloud.version&amp;gt;2022.0.4&amp;lt;/spring-cloud.version&amp;gt;
    &amp;lt;aws-lambda-events.version&amp;gt;3.9.0&amp;lt;/aws-lambda-events.version&amp;gt;
    &amp;lt;aws-lambda-java-core-version&amp;gt;1.1.0&amp;lt;/aws-lambda-java-core-version&amp;gt;
  &amp;lt;/properties&amp;gt;
  
  &amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;spring-boot-starter&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;

    &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;spring-cloud-function-adapter-aws&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;

    &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;com.amazonaws&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;aws-lambda-java-events&amp;lt;/artifactId&amp;gt;
      &amp;lt;version&amp;gt;${aws-lambda-events.version}&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;

    &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;com.amazonaws&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;aws-lambda-java-core&amp;lt;/artifactId&amp;gt;
      &amp;lt;version&amp;gt;${aws-lambda-java-core-version}&amp;lt;/version&amp;gt;
      &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
    &amp;lt;/dependency&amp;gt;

    &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;spring-boot-starter-test&amp;lt;/artifactId&amp;gt;
      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
    &amp;lt;/dependency&amp;gt;
  &amp;lt;/dependencies&amp;gt;

  &amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-cloud-dependencies&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;${spring-cloud.version}&amp;lt;/version&amp;gt;
        &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
        &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
  &amp;lt;/dependencyManagement&amp;gt;&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

      &lt;h3&gt;Thin layout plugin&lt;/h3&gt;

      &lt;p&gt;
        Before we can deploy our spring cloud function into the AWS lambda
        function, we must first build a thin jar of our project.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;p&gt;Why do we require a thin jar?&lt;/p&gt;
      &lt;br /&gt;

      &lt;p&gt;
        Spring Boot applications come with lots of libraries, and AWS Lambda
        provides a layer where we can upload our common library, and later, when
        establishing an AWS function, we can add those layers to our function.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;p&gt;
        We only provide our source code by producing a thin jar. We will
        additionally generate a bundled jar containing all of the libraries
        required to run our AWS Lambda layer.
      &lt;/p&gt;
      &lt;br /&gt;

      &lt;p&gt;
        Add the &lt;b&gt;spring-boot-thin-layout&lt;/b&gt; and &lt;b&gt;maven-shade-plugin&lt;/b&gt; plugins to the
        build tag to generate the thin and bundle jars.
      &lt;/p&gt;
      &lt;br /&gt;
      &lt;pre&gt;&lt;code class = "xml:brush"&gt; &amp;#x3C;build&amp;#x3E;
    &amp;#x3C;plugins&amp;#x3E;

      &amp;#x3C;plugin&amp;#x3E;
        &amp;#x3C;groupId&amp;#x3E;org.apache.maven.plugins&amp;#x3C;/groupId&amp;#x3E;
        &amp;#x3C;artifactId&amp;#x3E;maven-deploy-plugin&amp;#x3C;/artifactId&amp;#x3E;
        &amp;#x3C;configuration&amp;#x3E;
          &amp;#x3C;skip&amp;#x3E;true&amp;#x3C;/skip&amp;#x3E;
        &amp;#x3C;/configuration&amp;#x3E;
      &amp;#x3C;/plugin&amp;#x3E;

      &amp;#x3C;plugin&amp;#x3E;
        &amp;#x3C;groupId&amp;#x3E;org.springframework.boot&amp;#x3C;/groupId&amp;#x3E;
        &amp;#x3C;artifactId&amp;#x3E;spring-boot-maven-plugin&amp;#x3C;/artifactId&amp;#x3E;
        &amp;#x3C;dependencies&amp;#x3E;
          &amp;#x3C;!-- building thin jar for deploying into the AWS lambda, because dependencies
            are required at the runtime in the AWS lambda --&amp;#x3E;
          &amp;#x3C;dependency&amp;#x3E;
            &amp;#x3C;groupId&amp;#x3E;org.springframework.boot.experimental&amp;#x3C;/groupId&amp;#x3E;
            &amp;#x3C;artifactId&amp;#x3E;spring-boot-thin-layout&amp;#x3C;/artifactId&amp;#x3E;
            &amp;#x3C;version&amp;#x3E;${wrapper.version}&amp;#x3C;/version&amp;#x3E;
          &amp;#x3C;/dependency&amp;#x3E;
        &amp;#x3C;/dependencies&amp;#x3E;
        &amp;#x3C;configuration&amp;#x3E;
          &amp;#x3C;excludes&amp;#x3E;
            &amp;#x3C;exclude&amp;#x3E;
              &amp;#x3C;groupId&amp;#x3E;org.projectlombok&amp;#x3C;/groupId&amp;#x3E;
              &amp;#x3C;artifactId&amp;#x3E;lombok&amp;#x3C;/artifactId&amp;#x3E;
            &amp;#x3C;/exclude&amp;#x3E;
          &amp;#x3C;/excludes&amp;#x3E;
        &amp;#x3C;/configuration&amp;#x3E;
      &amp;#x3C;/plugin&amp;#x3E;

      &amp;#x3C;plugin&amp;#x3E;
        &amp;#x3C;groupId&amp;#x3E;org.apache.maven.plugins&amp;#x3C;/groupId&amp;#x3E;
        &amp;#x3C;artifactId&amp;#x3E;maven-shade-plugin&amp;#x3C;/artifactId&amp;#x3E;
        &amp;#x3C;configuration&amp;#x3E;
          &amp;#x3C;createDependencyReducedPom&amp;#x3E;false&amp;#x3C;/createDependencyReducedPom&amp;#x3E;
          &amp;#x3C;shadedArtifactAttached&amp;#x3E;true&amp;#x3C;/shadedArtifactAttached&amp;#x3E;
          &amp;#x3C;shadedClassifierName&amp;#x3E;aws&amp;#x3C;/shadedClassifierName&amp;#x3E;
        &amp;#x3C;/configuration&amp;#x3E;
      &amp;#x3C;/plugin&amp;#x3E;

    &amp;#x3C;/plugins&amp;#x3E;

  &amp;#x3C;/build&amp;#x3E;&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

      &lt;h3&gt;Write a Spring Cloud function to reverse a given string.&lt;/h3&gt;

      &lt;p&gt;
        We'll start by writing a function and annotating it with the &lt;b&gt;@Bean&lt;/b&gt;
        annotation. As a result, it will be triggered when we run the AWS lambda
        code.
      &lt;/p&gt; &lt;br/&gt;

      &lt;pre&gt;&lt;code class = "java:brush"&gt; package in.learnjavaskills.springcloudfunctionawslambda;

 import in.learnjavaskills.springcloudfunctionawslambda.dto.GatewayRequest;
 import in.learnjavaskills.springcloudfunctionawslambda.dto.GatewayResponse;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.annotation.Bean;

 import java.util.Objects;
 import java.util.function.Function;

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

   @Bean
   public Function&amp;lt;GatewayRequest, GatewayResponse&amp;gt; reverseTextFunction()
   {
     return gatewayRequest -&amp;gt; {
       if (Objects.nonNull(gatewayRequest) &amp;amp;&amp;amp; Objects.nonNull(gatewayRequest.getText()))
       {
         String reverseText = new StringBuffer(gatewayRequest.getText()).reverse().toString();
         return new GatewayResponse(200, reverseText, &amp;quot;Success&amp;quot;);
       }
       return new GatewayResponse(409, null, &amp;quot;fail&amp;quot;);
     };
   }
 }
&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

      &lt;p&gt;
        As you can see from the code above, I used &lt;u&gt;GatewayRequest&lt;/u&gt; and
        &lt;u&gt;GatewayResponse&lt;/u&gt; to accept the user request and return the result. In our
        code, let us create both POJOs and &lt;a href="https://www.learnjavaskills.in/2023/09/what-is-a-record-in-java.html"&gt;record&lt;/a&gt;.
      &lt;/p&gt; &lt;br/&gt;

      &lt;pre&gt;&lt;code class = "java:brush"&gt; public class GatewayRequest
 {
   private String text;

   public String getText()
   {
     return text;
   }
   // Getter and Setter, toString, equal and hashcode methods
 }&lt;/code&gt;&lt;/pre&gt;
      &lt;br /&gt;

      &lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.springcloudfunctionawslambda.dto;

 public record GatewayResponse(int status, String reverseText, String message)
 {} &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

      &lt;p&gt;
        For the &lt;u&gt;GatewayResponse&lt;/u&gt;, I have use a &lt;a href="https://www.learnjavaskills.in/2023/09/what-is-a-record-in-java.html"&gt;record&lt;/a&gt;. You can utilize Java Pojo
        in your Spring Cloud function if you are running &lt;b&gt;Java 8&lt;/b&gt; or &lt;b&gt;Java 11&lt;/b&gt;.
      &lt;/p&gt; &lt;br/&gt;

      &lt;h3&gt;Create packages for AWS Lambda deployment.&lt;/h3&gt;

      &lt;p&gt;Let's create a package by running the following command:&lt;/p&gt; &lt;br/&gt;

      &lt;blockquote&gt; mvn clean install &lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt;
      &lt;br/&gt;

      &lt;p&gt;
        After successfully building the package, you should see the following
        jar in the targer folder:
      &lt;/p&gt; 

      &lt;div class="separator" style="clear: both;"&gt;
        &lt;a
          href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAj_tXNjLGA3lsJf5S1KzFsAUXSTM3M6k5PPXhYouJXrdUimdf-2ylaXa2Ww1OX8vJ70l0AfQnW3Ve9vhPMrZiPWlYX1CSy4DSfiVEGQJD4IqQY0It2uQ0R50uq8PYRyAXKS4pZBkzdx3GmhNM6M1rXz0nfeaDpNXiQFxW6wGA6rObzoEJotczVyvD_EvX/s1600/target-folder.png"
          style="display: block; padding: 1em 0; text-align: center; "
          &gt;&lt;img
            alt="target folder structure with jar"
            border="0"
            data-original-height="224"
            data-original-width="461"
            src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAj_tXNjLGA3lsJf5S1KzFsAUXSTM3M6k5PPXhYouJXrdUimdf-2ylaXa2Ww1OX8vJ70l0AfQnW3Ve9vhPMrZiPWlYX1CSy4DSfiVEGQJD4IqQY0It2uQ0R50uq8PYRyAXKS4pZBkzdx3GmhNM6M1rXz0nfeaDpNXiQFxW6wGA6rObzoEJotczVyvD_EvX/s1600/target-folder.png"
        /&gt;&lt;/a&gt;
      &lt;/div&gt;
      
      &lt;p&gt;We are only interested in &lt;b&gt;spring-cloud-function-aws-lambda-0.0.1-SNAPSHOT.jar&lt;/b&gt; and &lt;b&gt;spring-cloud-function-aws-lambda-0.0.1-SNAPSHOT-aws.jar&lt;/b&gt; for the time being. Which will be used in the &lt;u&gt;AWS Lambda function and AWS Lambda Layer&lt;/u&gt;.&lt;/p&gt;
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;br/&gt;

&lt;div&gt;
  &lt;h2&gt;Set up the AWS Lambda Function with the Spring Cloud Function.&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;You must have an active AWS account before attempting this activity. If you don't already have an AWS account, you may sign up for a 12-month free tier account from &lt;a href="https://aws.amazon.com/free/?trk=09863622-0e2a-4080-9bba-12d378e294&amp;amp;sc_channel=ps&amp;amp;ef_id=Cj0KCQjwusunBhCYARIsAFBsUP9lybaI8rWnnhOJbLpXuiqZ_kWPRSkHxi_kgmHhig5Oh_MBrrYrGEsaArYIEALw_wcB:G:s&amp;amp;s_kwcid=AL!4422!3!453325184878!e!!g!!aws%20console!10712784862!111477280451&amp;amp;all-free-tier.sort-by=item.additionalFields.SortRank&amp;amp;all-free-tier.sort-order=asc&amp;amp;awsf.Free%20Tier%20Types=*all&amp;amp;awsf.Free%20Tier%20Categories=*all" target="_blank" rel="nofollow"&gt;here&lt;/a&gt;.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Log into your AWS Lambda account, select the nearest region, and then search for &lt;u&gt;AWS Lambda&lt;/u&gt; in the search field, as seen in the image below.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;I'm working in the Mumbai region for this activity.&lt;/p&gt; &lt;br/&gt;
  
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOFcb4IFMtjGsFPhKZxRpl4InWbhQcGFFXoYqlDWnAHEZgx1fhC0RowM19UBXroYfCopFjgJMuuFox6_HM788rb1Zmy8ZuwwboRLieBXi5jWkjoh7-QUvQhnZndV2bJbQUuJJMagycak9cGrAuLofZEGsIWGRfFjaoQQOJfTzTMntbYnr3TtXa0QaeVJNS/s1600/lambda-search.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="search-aws-lambda-from-aws-console" border="0" data-original-height="507" data-original-width="909" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOFcb4IFMtjGsFPhKZxRpl4InWbhQcGFFXoYqlDWnAHEZgx1fhC0RowM19UBXroYfCopFjgJMuuFox6_HM788rb1Zmy8ZuwwboRLieBXi5jWkjoh7-QUvQhnZndV2bJbQUuJJMagycak9cGrAuLofZEGsIWGRfFjaoQQOJfTzTMntbYnr3TtXa0QaeVJNS/s1600/lambda-search.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;After successfully completing the lambda search, you will be directed to the AWS lambda function's home page, as seen below.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;To create a new lambda function, click the &lt;b&gt;create a function&lt;/b&gt; button.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOno3jdU5Jq8_mFZFLaVflMvk4R8-YbnCUgKXZ-i7rgSNh5KfJMzJGDsWQcgYPgBk7FDjr8rGWOU7DZqpsKWfl3XAL-EbuGzT0qUiMRUErsz_OXUH3ouAs1zFth1tpXunGz2H3F4ceqDcP3FQOb3I6HhZy-FTwlXcPTe1rQG24ksHIH4PunqhGwpCgLwIT/s1600/lambda-home-screen.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="aws-lambda-home-screen" border="0" data-original-height="334" data-original-width="1163" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOno3jdU5Jq8_mFZFLaVflMvk4R8-YbnCUgKXZ-i7rgSNh5KfJMzJGDsWQcgYPgBk7FDjr8rGWOU7DZqpsKWfl3XAL-EbuGzT0qUiMRUErsz_OXUH3ouAs1zFth1tpXunGz2H3F4ceqDcP3FQOb3I6HhZy-FTwlXcPTe1rQG24ksHIH4PunqhGwpCgLwIT/s1600/lambda-home-screen.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;You'll now be asked to choose a function creation option. We must select the &lt;b&gt;author from scratch&lt;/b&gt; option from the screen given below because we will be deploying our own Spring Cloud service.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4RjC36rvjZH06TPdGp1IX6g5VvYwD8lnS9WAX4jajiAeRLxXYYqOVDtKbgigUXiYG8LEfRdAmskPf2HcVh92zWkN_hY4WIJuLK9RRBe9z1VoYAEmMnuqvCNv0tfIm7KvG6yLvE0qbnL8V290ytlCIdHQXMdHRN2Ym7Ms8lH9rF_O9juN5G7rf67VpmKBA/s1600/create-function.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="create-aws-lambda-function-screen" border="0" data-original-height="225" data-original-width="1258" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4RjC36rvjZH06TPdGp1IX6g5VvYwD8lnS9WAX4jajiAeRLxXYYqOVDtKbgigUXiYG8LEfRdAmskPf2HcVh92zWkN_hY4WIJuLK9RRBe9z1VoYAEmMnuqvCNv0tfIm7KvG6yLvE0qbnL8V290ytlCIdHQXMdHRN2Ym7Ms8lH9rF_O9juN5G7rf67VpmKBA/s1600/create-function.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;Let's fill out the &lt;u&gt;Basic Information&lt;/u&gt; box with the lambda &lt;b&gt;function name&lt;/b&gt; and &lt;b&gt;runtime version&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;I named it &lt;u&gt;spring-cloud-function-with-spring-boot-version-3&lt;/u&gt; because I used Spring Boot version 3 instead of Spring Boot version 2 since Spring Boot version 2 has various setups, which I'll illustrate later.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Because I use open JDK 17 in order to build the Spring cloud function on my machine, the runtime version is &lt;b&gt;Java 17&lt;/b&gt;. You can change the Java version to match your JDK version.&lt;/p&gt; &lt;br/&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizk7dmYeucOMRATxXMAF1OjPzJf4QlPGdLtF8QHKSn7RmOiqfYGKCDYX_fMWN2f86XuPcHPNCHQb_XYWDxgtYZq409P7GK6LXtwHJdxiIYwJD1-tf_PnfSusEtUAlfOYjeOgrJguQLTT47dZOqs9MjPK7lJvoSIAi5bU0QvQgyLO8MNGQ4Q-wmd6mscPE4/s1600/Basic-informationUntitled.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="aws-lambda-basic-information-screen" border="0" data-original-height="552" data-original-width="1223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizk7dmYeucOMRATxXMAF1OjPzJf4QlPGdLtF8QHKSn7RmOiqfYGKCDYX_fMWN2f86XuPcHPNCHQb_XYWDxgtYZq409P7GK6LXtwHJdxiIYwJD1-tf_PnfSusEtUAlfOYjeOgrJguQLTT47dZOqs9MjPK7lJvoSIAi5bU0QvQgyLO8MNGQ4Q-wmd6mscPE4/s1600/Basic-informationUntitled.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;Once you've completed all of the steps, you may use the &lt;b&gt;create function&lt;/b&gt; button to create your first AWS lambda function.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2cnCWe37KFAFsqvIVW9RrLFiFNMnf8GQIiM2dG_BJ59qHN0-Qp8g6hsctLm-uwgPKuR64Ijgx3tDMqro5IpfIYXR50y3XxQmOdM9qylDNZeS-ZcmaefsVcs_AwW35gcXv-oMSJ14prF2JWIqjEZxS898FTrwLrf6Up4gH9coXZzUG6ap2LaEYtQWzAIFh/s1600/create-function-button.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="create-function-image" border="0" data-original-height="133" data-original-width="1237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2cnCWe37KFAFsqvIVW9RrLFiFNMnf8GQIiM2dG_BJ59qHN0-Qp8g6hsctLm-uwgPKuR64Ijgx3tDMqro5IpfIYXR50y3XxQmOdM9qylDNZeS-ZcmaefsVcs_AwW35gcXv-oMSJ14prF2JWIqjEZxS898FTrwLrf6Up4gH9coXZzUG6ap2LaEYtQWzAIFh/s1600/create-function-button.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;When you use the &lt;u&gt;create function&lt;/u&gt; button, your first AWS lambda has been successfully created. You can confirm this by looking at the screen below.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf7yN-MfVz0JPM0wCspkLtV0L5HRnVwPuKWismkCN0oo2_DyYBmefZJHTPJdwkFFe4NbKMEtyS_sxUCaeaCP8j8UNxo4zfytw1roHTeXuv8sHEns0vfsnTf3ANV_MmT5p6N2v_J9bH2WDWlm7QifZNZarxIlZZHCHS3RFB2VNfKN8k0mvpB2FJSqSQdpP7/s1600/lambda-function-created-home-screen.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="aws-lambda-function-created-succesfully-image" border="0" data-original-height="587" data-original-width="1268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf7yN-MfVz0JPM0wCspkLtV0L5HRnVwPuKWismkCN0oo2_DyYBmefZJHTPJdwkFFe4NbKMEtyS_sxUCaeaCP8j8UNxo4zfytw1roHTeXuv8sHEns0vfsnTf3ANV_MmT5p6N2v_J9bH2WDWlm7QifZNZarxIlZZHCHS3RFB2VNfKN8k0mvpB2FJSqSQdpP7/s1600/lambda-function-created-home-screen.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;Are all of our AWS Lambda configurations complete?&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Surprisingly, we have yet to deploy our spring cloud function code into the AWS Lambda function.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Remember that we made two jars. &lt;u&gt;Spring-cloud-function-aws-lambda-0.0.1-SNAPSHOT.jar&lt;/u&gt; was one, and &lt;u&gt;spring-cloud-function-aws-lambda-0.0.1-SNAPSHOT-aws.jar&lt;/u&gt; was the other.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;It's time to deploy one of those jars into the lambda function. The &lt;u&gt;spring-cloud-function-aws-lambda-0.0.1-SNAPSHOT.jar&lt;/u&gt; package jar is our thin jar, which we are now putting into our AWS Lambda function.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Scroll down to the &lt;b&gt;code&lt;/b&gt; portion of the AWS Lambda function, where you will find the &lt;b&gt;upload from&lt;/b&gt; button, as seen in the image below. To deploy &lt;u&gt;spring-cloud-function-aws-lambda-0.0.1-SNAPSHOT.jar&lt;/u&gt;, click the upload from button.&lt;/p&gt; 
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaplgmtTOoHDPRE6Zq4m303KS_K-aNfAPoN6J_L98AnvO_zn0G0l-0I2WRKVs8zO5E162W0CCz3WGUhwHKwwFqx7QEZ0rLQ3b69ZqBbfYYdkj327HvLgJkfq2gpHgIaAEB8fVQ9qCPs0T12WU9LmeBEJWx5n6JtOKPOz55jV1MD3CMMwV-IoWhCg-pAfEw/s1600/upload-from-button.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="uploading-artifact-in-aws-lambda-function-screen" border="0" data-original-height="252" data-original-width="1234" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaplgmtTOoHDPRE6Zq4m303KS_K-aNfAPoN6J_L98AnvO_zn0G0l-0I2WRKVs8zO5E162W0CCz3WGUhwHKwwFqx7QEZ0rLQ3b69ZqBbfYYdkj327HvLgJkfq2gpHgIaAEB8fVQ9qCPs0T12WU9LmeBEJWx5n6JtOKPOz55jV1MD3CMMwV-IoWhCg-pAfEw/s1600/upload-from-button.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  
  &lt;p&gt;In the aws lambda function, you have two options for uploading your artifact or jar. You can either zip your artifact or jar before uploading it to the lambda function, or you can immediately upload your jar.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Second, you can upload your artifact or jar into the &lt;u&gt;AWS S3 bucket&lt;/u&gt; and then selecting it into the AWS lambda function to upload it.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;In our example, we are uploading our jar directly into the AWS Lambda function by using the.zip or.jar option.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJJ4f4ln_FW2cXzAvQUMUIn5_QHSigG1CdQc7YuzBasOlZk7lPDBKTuOmaXfpqe6pvi8UZ4YA3TGuAf9XDbE5F8LWkHwN0DGdmg9p5xq2RCYAFSdX_3tSCiQgNs0ZNYBPPZ9hd-sUyvehRGFYlk2HkA4MBBeRmLlulPNUf-9i88sWo_JspnKSioBWFdFxo/s1600/two-option-in-upload-button.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="two-option-in-uploading-artifact-screen" border="0" data-original-height="248" data-original-width="1223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJJ4f4ln_FW2cXzAvQUMUIn5_QHSigG1CdQc7YuzBasOlZk7lPDBKTuOmaXfpqe6pvi8UZ4YA3TGuAf9XDbE5F8LWkHwN0DGdmg9p5xq2RCYAFSdX_3tSCiQgNs0ZNYBPPZ9hd-sUyvehRGFYlk2HkA4MBBeRmLlulPNUf-9i88sWo_JspnKSioBWFdFxo/s1600/two-option-in-upload-button.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;An upload box will appear, allowing you to select your jar, which will be deployed into the AWS Lambda function. Click the upload button, navigate to the jar in your file explorer, and then click the save button.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT_ioD-jR0N1Tm4ohumTsX3qeUosDKgLbjVlt4Zm4cHRFVTaHfFd_qX0XsUfK1norLE24kuVr-RSOuSXqc0H45vXOpWHD0w3kimRCy1OYNMp91ajAurlwFdrKhyZnP8CBv38aE5rBpT2w7jIFCnqLO1cuNyWpo_YAVUOibXp33gcLWldlxKYMw7Vn-2FPu/s1600/upload-zip-jar--window.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="select-jar-file-from-file-explorer" border="0" data-original-height="345" data-original-width="833" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT_ioD-jR0N1Tm4ohumTsX3qeUosDKgLbjVlt4Zm4cHRFVTaHfFd_qX0XsUfK1norLE24kuVr-RSOuSXqc0H45vXOpWHD0w3kimRCy1OYNMp91ajAurlwFdrKhyZnP8CBv38aE5rBpT2w7jIFCnqLO1cuNyWpo_YAVUOibXp33gcLWldlxKYMw7Vn-2FPu/s1600/upload-zip-jar--window.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  
  &lt;p&gt;Congratulation, Your thin jar was successfully uploaded to the AWS lambda function. You may validate this by looking at the screen below on your AWS Lambda Function page:&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj51go32dDFVNh36NQOmgI2D29yg1L4p4oAlQmWGk2TpwSaA6xFYs1BiNENTzh-f3e1aiB0iZ69ARjDVS4eFwcllrx83-o7uTXgdz2MMh4XFTGZpf4uyXlIw5zkaPan7ev6hwUYM0CRNERcCq8WIo2y0FQBWoh_QkQBu0lUE-I9qqN1pMnNTkhz6VdQfd3j/s1600/success-scrren-file-uploaded.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="success-scrren-of-uploading-file" border="0" data-original-height="47" data-original-width="1272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj51go32dDFVNh36NQOmgI2D29yg1L4p4oAlQmWGk2TpwSaA6xFYs1BiNENTzh-f3e1aiB0iZ69ARjDVS4eFwcllrx83-o7uTXgdz2MMh4XFTGZpf4uyXlIw5zkaPan7ev6hwUYM0CRNERcCq8WIo2y0FQBWoh_QkQBu0lUE-I9qqN1pMnNTkhz6VdQfd3j/s1600/success-scrren-file-uploaded.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  
  &lt;h2&gt;Adding a layer to the AWS layer or installing a dependent Spring cloud function library&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;Is our Aws Lambda function suitable for testing?&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Unfortunately, it is not. We still need to deploy our spring cloud function library into the AWS layer and connect it to our AWS lambda function. Till now we have only deployed our code into the AWS lambda function.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Let's make a layer and insert our jar into it.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Hit the three horizontal lines in the top left sidebar to expand the side bar menu, and then select the &lt;b&gt;layer&lt;/b&gt; as shown in the screenshot below.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWh6SqJGhoaUdiW_eanKyQrWHboPl38fwalTict-_GT9BbJVzTlS2HEujzV0rKJWedhBFveMSeT2EzZSY3ocH0XBQSHyMz-23D2QqYzra8NryHQtOww6j1iuFU8cpFWXr36qwADxFLZhdkgzCxkF2wN0D67aES06x7yrkuO3WpAdFYA38likvU-LkA1CpC/s1600/Layer-select-option.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="lambda-side-bar-to-choose-layer" border="0" data-original-height="462" data-original-width="281" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWh6SqJGhoaUdiW_eanKyQrWHboPl38fwalTict-_GT9BbJVzTlS2HEujzV0rKJWedhBFveMSeT2EzZSY3ocH0XBQSHyMz-23D2QqYzra8NryHQtOww6j1iuFU8cpFWXr36qwADxFLZhdkgzCxkF2wN0D67aES06x7yrkuO3WpAdFYA38likvU-LkA1CpC/s1600/Layer-select-option.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;You'll now be taken to the layer's main screen. To begin generating a layer, click the &lt;b&gt;create layer&lt;/b&gt; button, as seen below.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDqi6dmtgqe_QKCnJxKESa1sL6Vsi_c9WFGS1JCh7wjEImnbCNtSpBGeP3MSz0VJ63h4MT6Q2Xj74BXmWlmf6eHnMRD2RRwgjFGtodKijb7PyRkpbCFZBhNd88Ngtd4skO0C_pNne4zzRfVEIODgAiuewinArEmEfvqcgkBv95ud5VBb51Ks4OhEIZl4kS/s1600/create-layer-button.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="create-layer-button" border="0" data-original-height="264" data-original-width="1004" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDqi6dmtgqe_QKCnJxKESa1sL6Vsi_c9WFGS1JCh7wjEImnbCNtSpBGeP3MSz0VJ63h4MT6Q2Xj74BXmWlmf6eHnMRD2RRwgjFGtodKijb7PyRkpbCFZBhNd88Ngtd4skO0C_pNne4zzRfVEIODgAiuewinArEmEfvqcgkBv95ud5VBb51Ks4OhEIZl4kS/s1600/create-layer-button.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;To upload the &lt;u&gt;spring-cloud-function-aws-lambda-0.0.1-SNAPSHOT-aws.jar&lt;/u&gt; into the layer, zip the artifact into the &lt;b&gt;java/lib&lt;/b&gt; folder.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Complete the &lt;u&gt;layer configuration&lt;/u&gt; form. You can enter any name in the name text box, however for this example, I'm using &lt;u&gt;spring-cloud-function-library&lt;/u&gt;.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Even if it is optional, don't forget to fill out the description. It will assist you in determining which libraries are included in this layer.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Upload your zip file, choose a compatible runtime (for us, Java 17), and click the Create button.&lt;/p&gt; &lt;br/&gt;
  
  &lt;blockquote&gt;The AWS Lambda function allows us to upload a jar with a maximum size of 50 MB, and if the jar size is larger than or equivalent to 10 MB, we should use AWS S3.(alert-success)&lt;/blockquote&gt; &lt;br/&gt;
  
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv-O4184-NNPLGTSDpGYSQUAlMIwyL5eNZKLFPh1hPU6vz3HMBYyFclyUyQPpMRKEMO5yqZzMldNYpHDbWjVN6_ulE9X-n4eufMxIvqauafE-fH6zaVGXHOzltgWcYvpRlMaFPJQZuaEPbBuWocOH-tHqSJUwgeznb58gecO0gOW-CIQ54JqM_sRxcZnDT/s1600/layer-upload-screen.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="layer-configuration-screen" border="0" data-original-height="535" data-original-width="619" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv-O4184-NNPLGTSDpGYSQUAlMIwyL5eNZKLFPh1hPU6vz3HMBYyFclyUyQPpMRKEMO5yqZzMldNYpHDbWjVN6_ulE9X-n4eufMxIvqauafE-fH6zaVGXHOzltgWcYvpRlMaFPJQZuaEPbBuWocOH-tHqSJUwgeznb58gecO0gOW-CIQ54JqM_sRxcZnDT/s1600/layer-upload-screen.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu_0Kvinz15rXNQQ7l5dwdxqqeXvCPF_y38YJckn-BFwG3RU_Ri9rzLDxgqaHSM5uGZ_W3RzTvHj4hxOrJzLcHTX6IwdRSpnwagaQZJCpTaRjxcnatWk60r_vnZ3mZikHvd_635XSBre1ON1CZEMaYfG59BbHHKeeVW8JaL5U_BhZBZsQbJ9TIisln4Qyh/s1600/layer-compatable-runtime-option.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="runtime-version-chosse-for-layer" border="0" data-original-height="333" data-original-width="815" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu_0Kvinz15rXNQQ7l5dwdxqqeXvCPF_y38YJckn-BFwG3RU_Ri9rzLDxgqaHSM5uGZ_W3RzTvHj4hxOrJzLcHTX6IwdRSpnwagaQZJCpTaRjxcnatWk60r_vnZ3mZikHvd_635XSBre1ON1CZEMaYfG59BbHHKeeVW8JaL5U_BhZBZsQbJ9TIisln4Qyh/s1600/layer-compatable-runtime-option.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;Hurray! We have finished developing a layer in AWS lambda. Look at the screen below to confirm your layer creation.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl-NZYRfuMnlwuKEvUX6Uw57-OkmgHqeUUtwVbghBfQ2n2JKYpB0NHlU6FwITr7elbmObKil4aI7cpkvLKctf-Pt-qbenW-veENTcmtjEzii2EPmumk0lzScdV-ZMINMqS8Kwcg8TAtQiRAgyVNM1oMwQcYYq_OqxRUfyxaVbu8Lx6JXI6im94tkuQlub8/s1600/layer-created-succesfully.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Layer-Created-Successfully" border="0" data-original-height="436" data-original-width="1263" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl-NZYRfuMnlwuKEvUX6Uw57-OkmgHqeUUtwVbghBfQ2n2JKYpB0NHlU6FwITr7elbmObKil4aI7cpkvLKctf-Pt-qbenW-veENTcmtjEzii2EPmumk0lzScdV-ZMINMqS8Kwcg8TAtQiRAgyVNM1oMwQcYYq_OqxRUfyxaVbu8Lx6JXI6im94tkuQlub8/s1600/layer-created-succesfully.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;h3&gt;Attached layer into the AWS Lambda Function&lt;/h3&gt;
  
  &lt;p&gt;It's finally time to connect this layer to the AWS lambda function.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Open your lambda function, then scroll down until you find the &lt;b&gt;layers&lt;/b&gt; section. To add a layer to this AWS lambda function, locate the &lt;b&gt;add layer&lt;/b&gt; button.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfk2ozLdZdd8c0XzgxCGq0yITBH2eGeAX9MICN_5ljce9_67qv8jbAgHsTdOMbH7q97vKcoyCzXtKEQQQcXWamvWU_-OWviDkTG_Urq0_eOkp5z8mK548jhwrDJY-9em5wdh7DuRoRKsDsIWXF87RfwEdeNNH7o_Qqg_mGv90HTPHdxbzz3W_ggqkXWsUi/s1600/add-layer-to-lambda-function.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="add layer button screen on lambda function" border="0" data-original-height="180" data-original-width="1216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfk2ozLdZdd8c0XzgxCGq0yITBH2eGeAX9MICN_5ljce9_67qv8jbAgHsTdOMbH7q97vKcoyCzXtKEQQQcXWamvWU_-OWviDkTG_Urq0_eOkp5z8mK548jhwrDJY-9em5wdh7DuRoRKsDsIWXF87RfwEdeNNH7o_Qqg_mGv90HTPHdxbzz3W_ggqkXWsUi/s1600/add-layer-to-lambda-function.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
 
  &lt;p&gt;The Add Layer dialog box will display. Select the Custom Layer radio button under the Choose Layer section, and then select the &lt;u&gt;spring-cloud-function-library&lt;/u&gt; that we recently generated under the Customer Layer drop-down.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Don't forget to select the layer's version. Because this is the first time we are deploying it, it will be version 1.&lt;/p&gt;
  
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaPqjrNDGr2zIqFZ3HQh_mMsJR5y0E9FRYtZvSqciK3hgy8duW7-v2_VIrdG3JtkhY8mrqky3lc6Mb_uvnGiZ89FSJCCVBE3s3pKMPBHrQ3MuWCc4OGpxMzxOmRVZcdSh4oljinspfwxJd67ZqZYvSh7EplfsdL8mVM33clvUrA3S8PNnGMRFg090ZIuE_/s1600/add-layer-option1.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="add layer dialog box 1" border="0" data-original-height="263" data-original-width="834" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaPqjrNDGr2zIqFZ3HQh_mMsJR5y0E9FRYtZvSqciK3hgy8duW7-v2_VIrdG3JtkhY8mrqky3lc6Mb_uvnGiZ89FSJCCVBE3s3pKMPBHrQ3MuWCc4OGpxMzxOmRVZcdSh4oljinspfwxJd67ZqZYvSh7EplfsdL8mVM33clvUrA3S8PNnGMRFg090ZIuE_/s1600/add-layer-option1.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbwBaQRVK6O0d-wMftab0MxQ9TXoTt5Mb5CWBuQuKDhaFD7r-FX_oYYWu-WlTGVDtM_VvR6EMgMpQctfga9JhCB8AD0nUauzuVX-kxjvD9HLvrTRlKlKUkP2USFhz9MBq4uD__27WdjjH-lwXriw29EQDksZ1yofSQP_i_kYmSnReniiadNjCIX0i3pEVX/s1600/add-layer-option2.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="add layer dialog box 2" border="0" data-original-height="487" data-original-width="843" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbwBaQRVK6O0d-wMftab0MxQ9TXoTt5Mb5CWBuQuKDhaFD7r-FX_oYYWu-WlTGVDtM_VvR6EMgMpQctfga9JhCB8AD0nUauzuVX-kxjvD9HLvrTRlKlKUkP2USFhz9MBq4uD__27WdjjH-lwXriw29EQDksZ1yofSQP_i_kYmSnReniiadNjCIX0i3pEVX/s1600/add-layer-option2.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;The layer will be successfully added once you press the add button. You can see if it's been added or not by looking at the layer section.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-jm8inZQu4U3OKu8dp6jelAsuiKneI72Y6Ybycck5aNMusOpOFgERZMagOJZTOo9x43ns84Rj_vN7hpRNyhPQiX8PfVFe5Vt8PuodSacNzY2qtESShZr6A_aLS0nGZxu6vIRLUuhBStueErZeuR-MH59tXfNZkOBm4CLLDuwSPQCnBqRL2prbW3fi6VK5/s1600/layer-added.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="layer-added screen" border="0" data-original-height="176" data-original-width="1230" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-jm8inZQu4U3OKu8dp6jelAsuiKneI72Y6Ybycck5aNMusOpOFgERZMagOJZTOo9x43ns84Rj_vN7hpRNyhPQiX8PfVFe5Vt8PuodSacNzY2qtESShZr6A_aLS0nGZxu6vIRLUuhBStueErZeuR-MH59tXfNZkOBm4CLLDuwSPQCnBqRL2prbW3fi6VK5/s1600/layer-added.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  

  &lt;blockquote&gt;The layer's maximum zip file size is 250 MB, and you can add up to 5 layers in one AWS lambda function.(alert-passed)&lt;/blockquote&gt; &lt;br/&gt;
  
&lt;/div&gt;

&lt;div&gt;

&lt;h2&gt;Configure the handler in the AWS lambda function&lt;/h2&gt;
  &lt;hr&gt;

&lt;p&gt;To use the aws lambda function, we must first configure the request handler.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The &lt;b&gt;org.springframework.cloud.function.adapter.aws.FunctionInvoker&lt;/b&gt; is one of the generic request handlers that is implemented in the AWS RequestStreamHandler.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Navigate to the runtime settings and click the edit button, as seen in the figure below.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHICLrNyWi9L1gLU7Zo5o1Tu5UQ378hcWTNmsQPK6oNMk-f63Te076Nanht2fH8jkC0B__3i6aI7YVTxt55ep-ZiY8FKYZ3RC1SmVyK-NyXZN7V_1a0y6OZwmeKuvurWmzoxiWD96bAOEL7MkYL9r0yRybNNB0C3FKBAak3c_tmD6PSWqxJz_0wTJhPpl6/s1600/runtime-setting.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="runtime-setting" border="0" data-original-height="212" data-original-width="1209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHICLrNyWi9L1gLU7Zo5o1Tu5UQ378hcWTNmsQPK6oNMk-f63Te076Nanht2fH8jkC0B__3i6aI7YVTxt55ep-ZiY8FKYZ3RC1SmVyK-NyXZN7V_1a0y6OZwmeKuvurWmzoxiWD96bAOEL7MkYL9r0yRybNNB0C3FKBAak3c_tmD6PSWqxJz_0wTJhPpl6/s1600/runtime-setting.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Change the name of the handler to &lt;b&gt;org.springframework.cloud.function.adapter.aws.FunctionInvoker&lt;/b&gt; as shown in the figure below, and then click the save button.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEwueyu80ue06q1s4yfa6rwh5YNJLKnylijBK8gHKzQHyeYCUKn8NETFMghm0RHE0TWpjyo4ClseAfG3q_FX9nOlphAg4rPiWTPHBBbjsuD7mdAlyB91TynlEyykL_C8Wdwj-ZyAO22Pd-rLC_epm8SO5yQl77lu59XHyjk-zxBWIb8pUhMjAsaexIjqWI/s1600/runtime-setting-handler.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="handler-setting-update" border="0" data-original-height="578" data-original-width="810" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEwueyu80ue06q1s4yfa6rwh5YNJLKnylijBK8gHKzQHyeYCUKn8NETFMghm0RHE0TWpjyo4ClseAfG3q_FX9nOlphAg4rPiWTPHBBbjsuD7mdAlyB91TynlEyykL_C8Wdwj-ZyAO22Pd-rLC_epm8SO5yQl77lu59XHyjk-zxBWIb8pUhMjAsaexIjqWI/s1600/runtime-setting-handler.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;div&gt;

&lt;h2&gt;AWS Lambda Function Testing&lt;/h2&gt;
  &lt;hr&gt;

&lt;p&gt;Hurray! We have completed all of the prerequisites required to run the AWs lambda function. However, before connecting this AWS lambda function to the API Gateway to build a rest API, we must first ensure that the function is functioning properly.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;To quickly validate the AWS lambda function, let's proceed to the test part.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The AWS lambda function offers us the ability to create an event to test our lambda function. Let's create an event with the name verify reverse string under the event JSON and send the following payload:&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4RE1rmgpO627s8aniWOkK8hoYmoIjZPWbVQ3yFS-Rx890CwUSoZRlyUtX_5UMurcaYrsusnkmJNK7a4qYgsbr0zcb9RoJV0bgSI1ZqtDqw9MYTy2HN0kXyXFVbfda2XAVdrmrlItOXY9uJQLYgbHp6ASDQxpBejrbLaZykrcBsWxVCEkGl7Znk1DXbP9S/s1600/test-event-creation.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="event creation" border="0" data-original-height="523" data-original-width="1230" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4RE1rmgpO627s8aniWOkK8hoYmoIjZPWbVQ3yFS-Rx890CwUSoZRlyUtX_5UMurcaYrsusnkmJNK7a4qYgsbr0zcb9RoJV0bgSI1ZqtDqw9MYTy2HN0kXyXFVbfda2XAVdrmrlItOXY9uJQLYgbHp6ASDQxpBejrbLaZykrcBsWxVCEkGl7Znk1DXbP9S/s1600/test-event-creation.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkx-APBcGTWn_PJp1RTFiOjNde81boYrAfsYX38m8m2ocAolLkKppQnshehTKlhns1xw-f2z68Vb-zeUABSyzaEHvohVk-3Sa7mF_rRb32_t6iIDA_FxB3mAAPS-PYq-f0FN6zKf6JKD1AT4v6T-Hvepp17eD-QNkcz67NqdqkzrpE79fpjmnHNzbUUAXr/s1600/test-payload.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="payload screen" border="0" data-original-height="224" data-original-width="1230" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkx-APBcGTWn_PJp1RTFiOjNde81boYrAfsYX38m8m2ocAolLkKppQnshehTKlhns1xw-f2z68Vb-zeUABSyzaEHvohVk-3Sa7mF_rRb32_t6iIDA_FxB3mAAPS-PYq-f0FN6zKf6JKD1AT4v6T-Hvepp17eD-QNkcz67NqdqkzrpE79fpjmnHNzbUUAXr/s1600/test-payload.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;After inserting the payload, click the save button, followed by the test button.&lt;/p&gt; &lt;br/&gt;
  
  &lt;blockquote&gt;The AWS Lambda function limits us to completing the execution of the entire function within 15 minutes, which implies we can only perform a function execution within 15 minutes.(alert-warning)&lt;/blockquote&gt; &lt;br/&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh35swj-787LwLxRwlGTGIWzT5mKj-A0EENCDyJP8fJIwrKR_i-SIzkXRLZvnx7JU5WESn3sF85mHnxpKmRUEVbvj0y0frY1Rr7xXnFyKu6lx0dcXhWRl1hfbbkqFekdGiDxiNB7UGneQUesTF-z03O95ollZx_zksc73zS_7Ei1BwyaGJDcf4J0QDF-frD/s1600/test-save-button.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="" border="0" data-original-height="386" data-original-width="1247" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh35swj-787LwLxRwlGTGIWzT5mKj-A0EENCDyJP8fJIwrKR_i-SIzkXRLZvnx7JU5WESn3sF85mHnxpKmRUEVbvj0y0frY1Rr7xXnFyKu6lx0dcXhWRl1hfbbkqFekdGiDxiNB7UGneQUesTF-z03O95ollZx_zksc73zS_7Ei1BwyaGJDcf4J0QDF-frD/s1600/test-save-button.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;When you press the test button, the AWS lambda will respond as seen in the figure below.&lt;/p&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW1WNslt9-5oyrC8iFeCLw8Q-u51p-DFMANT-NLXsgulmPRlYL4xyWo9jZfRIF9yVFUh6vRylsZ7TC9gtU_Eb8Q6m8FOc2kE39aJcE0wvv7nSNHrWYLjzG4kx3kMdrx03xgau9qneY-YzHVbhoALGXir8B22u1vWEt-_Fv5azK9SfxDRsl1kL35kv5GAS6/s1600/test-pass.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="testing the lambda function" border="0" data-original-height="519" data-original-width="1244" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW1WNslt9-5oyrC8iFeCLw8Q-u51p-DFMANT-NLXsgulmPRlYL4xyWo9jZfRIF9yVFUh6vRylsZ7TC9gtU_Eb8Q6m8FOc2kE39aJcE0wvv7nSNHrWYLjzG4kx3kMdrx03xgau9qneY-YzHVbhoALGXir8B22u1vWEt-_Fv5azK9SfxDRsl1kL35kv5GAS6/s1600/test-pass.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;You may debug your request trail by checking in the function's log, just like the response of the aws lambda.&lt;/p&gt; &lt;br/&gt;


&lt;/div&gt;

&lt;div&gt;
  &lt;h2&gt;Let's trigger our lambda function by creating the rest api using the API gateway&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;P&gt;There are various ways of launching an AWS Lambda function, but for the purposes of this demonstration, we'll use the AWS API Gateway to do it.&lt;/P&gt; &lt;br/&gt;
  
  &lt;p&gt;The publishing, monitoring, and security of restful webservices are all handled by the fully managed Amazon API Gateway service.&lt;/p&gt; &lt;br/&gt;
   
  &lt;p&gt;The AWS API gateway serves as the entrance point for your apps before connecting to the business logic.&lt;/p&gt; &lt;br/&gt;
  
  
  &lt;p&gt;Are you delighted to use the API gateway to launch your first AWS lambda? If so, expose the rest endpoint to call the lambda function.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Navigate to your AWS lambda function and look for the add trigger button, as seen in the screenshot below.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAf0FCV5-GKiqxCtqmjoNt94ouqfTWbP8KHiSKFx3CkuZVU7cK-VopHlggdj67mmx7TzGQwVUGtXS1iwfpPGq_c80NRp6HsBlc6eyfyipN-ghDJ_4QsUFdp8VfviLjt483DESJAGBEy1mxA78uHN0JEMhqUvMAjZtgRCfXLp0Dekkv23U1_ErAAYgk4S6l/s1600/add-trigger.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="add-trigger-button" border="0" data-original-height="514" data-original-width="1237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAf0FCV5-GKiqxCtqmjoNt94ouqfTWbP8KHiSKFx3CkuZVU7cK-VopHlggdj67mmx7TzGQwVUGtXS1iwfpPGq_c80NRp6HsBlc6eyfyipN-ghDJ_4QsUFdp8VfviLjt483DESJAGBEy1mxA78uHN0JEMhqUvMAjZtgRCfXLp0Dekkv23U1_ErAAYgk4S6l/s1600/add-trigger.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  
  &lt;p&gt;The Add Trigger Configuration window will now appear. Select the API gateway from the Trigger Configuration drop-down menu.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLerStqEPdhqZsxgoJ9WajSUTr05NRf8KAQdWeEH6DMJb8_l3ghQ0875obZWUnq_JDhUG_bFnX5iayvJUmmh867zNk5cnwsam_L19RIsrcS9hsD6U9tbpJGNfbrcmUDIzyl5jlR19VOzwS6ZAwCpz55Af53TgOOKtMnGael03HrmI8t5taVs9U9ypWg4O8/s1600/add-trigger-api-gateway.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="add-trigger-configuration-window-api-gateway-select" border="0" data-original-height="555" data-original-width="1294" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLerStqEPdhqZsxgoJ9WajSUTr05NRf8KAQdWeEH6DMJb8_l3ghQ0875obZWUnq_JDhUG_bFnX5iayvJUmmh867zNk5cnwsam_L19RIsrcS9hsD6U9tbpJGNfbrcmUDIzyl5jlR19VOzwS6ZAwCpz55Af53TgOOKtMnGael03HrmI8t5taVs9U9ypWg4O8/s1600/add-trigger-api-gateway.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;Select the new API from the intent radio button, and ensure that the HTTP API type is selected in the API time section.&lt;/p&gt; &lt;br/&gt;
  
  &lt;blockquote&gt;There are two ways to construct a restful webservice in the AWS API gateway, and they are as follows: &lt;br/&gt;
  &lt;b&gt;HTTP APIs:&lt;/b&gt; HTTP APIs have been designed with fewer functionalities and are less expensive than Rest APIs. &lt;br/&gt;
  &lt;b&gt;Rest APIs:&lt;/b&gt; In comparison to HTTP APIs, Rest APIs provide greater functionalities. If you require API keys, per-client throttling, request validation, AWS WAF integration, or private API endpoints, use REST APIs.(alert-success)&lt;/blockquote&gt; &lt;br/&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisavh88rBBVikinF02UBuRJHeL9APyPOWxmZh9r7Whci3FFww_KE_uVSUu_Auu87ZRksqMmNtN13W8o9mKPvwGtp3BtozHTi01rjmmjwlvT7m9g4tcUHSXKeXwRIsUC4etoeIfhbQzwvxYYgIQjHdpW_37o6MUVGiKOz6pHgbVx8ecs1OmZWn2zMijULIh/s1600/new-api.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="new-api-type-select" border="0" data-original-height="567" data-original-width="835" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisavh88rBBVikinF02UBuRJHeL9APyPOWxmZh9r7Whci3FFww_KE_uVSUu_Auu87ZRksqMmNtN13W8o9mKPvwGtp3BtozHTi01rjmmjwlvT7m9g4tcUHSXKeXwRIsUC4etoeIfhbQzwvxYYgIQjHdpW_37o6MUVGiKOz6pHgbVx8ecs1OmZWn2zMijULIh/s1600/new-api.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;Choose open from the security drop-down because we're making this API open, which means we won't require API authentication to use it, and then click the add button to configure the API gateway trigger into the AWS lambda function.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih77CgL5U4x52n3NMFqJyG-L2uJs5RxWUHjWmZU4E0D0C7j3yxxNfQFGqrNGLztSU1lKQk0mtJYf6I18h37Tl0FW2O0mX5_mf4y3IhC2zpzloDbTyh9kN_wna8TwcsF1TOJ2IPnqP7ufOebkQmOP8fZwxtyq-mhMPHhLhJ1tRMMAzGJLgoNmu7Bz1IZ5J2/s1600/security-api.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="security choose section of the api gateway" border="0" data-original-height="285" data-original-width="841" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih77CgL5U4x52n3NMFqJyG-L2uJs5RxWUHjWmZU4E0D0C7j3yxxNfQFGqrNGLztSU1lKQk0mtJYf6I18h37Tl0FW2O0mX5_mf4y3IhC2zpzloDbTyh9kN_wna8TwcsF1TOJ2IPnqP7ufOebkQmOP8fZwxtyq-mhMPHhLhJ1tRMMAzGJLgoNmu7Bz1IZ5J2/s1600/security-api.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;h3&gt;Use the API endpoint provided by the API Gateway to test the AWS lambda function.&lt;/h3&gt;
  
  &lt;p&gt;After clicking the add button, you can discover the API gateway that has been configured in the trigger section of the configuration.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;You will also be provided with the API endpoint for executing the AWS lambda function.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiMrzbE4jgErl7pxasExNffSnP53GLTG-K6cD_upXCli-plLBmN8humpC3e8Lht0rf7nnMurHtbJnY5YCWd70jrcJbpvjRJ0LtUKJEMm6TsfcrfzvGcoy8A4hg_N5l8XnMPLEEdkz6Hjz24sBsd3HunZL23tGGJfIBpqKgZCRHMH4Y9aOFEriLKlf2t_19/s1600/api-gateway-endpoint.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="API enpoint from the configuration" border="0" data-original-height="557" data-original-width="1252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiMrzbE4jgErl7pxasExNffSnP53GLTG-K6cD_upXCli-plLBmN8humpC3e8Lht0rf7nnMurHtbJnY5YCWd70jrcJbpvjRJ0LtUKJEMm6TsfcrfzvGcoy8A4hg_N5l8XnMPLEEdkz6Hjz24sBsd3HunZL23tGGJfIBpqKgZCRHMH4Y9aOFEriLKlf2t_19/s1600/api-gateway-endpoint.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;Let's put this AWS lambda function to the test now, utilizing the API endpoint supplied by the API Gateway.&lt;/p&gt; &lt;br/&gt;
  &lt;p&gt;Copy and paste the API endpoint into Postman, then submit the json payload under the body, and we want the content to be reversed from the response.&lt;/p&gt;
  
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTdfCgpa4YObNmhMyHVolTiTUEX1NwhztDr-ytvKnr-puPzL5wCz-P6E2p-2XOZ4QEEh6uveWJB5GogkSaM_AGL99HYVNZxIc7tRBOLMgtqn4ZgKa0ziLNU4tn_Rfd67mKGhnaGUtICyzurR0pGYefBJtFEdlnzGw0OgPVw9NOf4lT8qs7uEK6od_zj7iI/s1600/postman-response.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="api testing" border="0" data-original-height="472" data-original-width="931" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTdfCgpa4YObNmhMyHVolTiTUEX1NwhztDr-ytvKnr-puPzL5wCz-P6E2p-2XOZ4QEEh6uveWJB5GogkSaM_AGL99HYVNZxIc7tRBOLMgtqn4ZgKa0ziLNU4tn_Rfd67mKGhnaGUtICyzurR0pGYefBJtFEdlnzGw0OgPVw9NOf4lT8qs7uEK6od_zj7iI/s1600/postman-response.png"/&gt;&lt;/a&gt;&lt;/div&gt;
  
  
 &lt;p&gt;As we can see from the response, we were able to retrieve the expected response from the AWS lambda function. It represents that we were able to successfully configure the AWS API gateway for our AWS lambda function.&lt;/p&gt;
&lt;/div&gt;
  
  &lt;br/&gt;
  
  &lt;div&gt;
    
    &lt;h2&gt;How to build a spring cloud function in Spring Boot 2 and deliver it to AWS Lambda.&lt;/h2&gt;
    &lt;hr&gt;
    
    &lt;p&gt;We've seen how to establish a spring cloud function in Spring Boot version 3, however there are some minor code changes in Spring Boot version 2 that we'll go over right now.&lt;/p&gt; &lt;br/&gt;
    
    &lt;p&gt;Instead of generating a bean in Spring Boot version 2, we must first develop a handler class that will be responsible for extending the &lt;b&gt;SpringBootRequestHandler&lt;/b&gt; class.&lt;/p&gt; &lt;br/&gt;
    
    &lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.springcloudfunctionawslambda.handler;

 import in.learnjavaskills.springcloudfunctionawslambda.dto.GatewayRequest;
 import in.learnjavaskills.springcloudfunctionawslambda.dto.GatewayResponse;

 import org.springframework.cloud.function.adapter.aws.SpringBootRequestHandler;

 public class RequestHandler extends SpringBootRequestHandler&amp;lt;GatewayRequest, GatewayResponse&amp;gt;
 {}&lt;/code&gt; &lt;/pre&gt;
    
    &lt;p&gt;After you've successfully constructed a handler class, let's make one class that implements the Functiona interface. In this, we will override the &lt;b&gt;apply&lt;/b&gt; method, which is the functional interface's abstract method, and then add code to reverse and string.&lt;/p&gt; &lt;br/&gt;
    
    &lt;pre&gt;&lt;code class = "java:brush"&gt; package in.learnjavaskills.springcloudfunctionawslambda.handler;

 import in.learnjavaskills.springcloudfunctionawslambda.dto.GatewayRequest;
 import in.learnjavaskills.springcloudfunctionawslambda.dto.GatewayResponse;
 import org.springframework.stereotype.Service;

 import java.util.Objects;
 import java.util.function.Function;

 @Service
 public class RequestHandlerService implements Function&amp;lt;GatewayRequest, GatewayResponse&amp;gt;
 {

   @Override
   public GatewayResponse apply(GatewayRequest gatewayRequest)
   {
     if (Objects.nonNull(gatewayRequest) &amp;amp;&amp;amp; Objects.nonNull(gatewayRequest.getText()))
     {
       String reverseText = new StringBuffer(gatewayRequest.getText()).reverse().toString();
       return new GatewayResponse(200, reverseText, &amp;quot;Success&amp;quot;);
     }
     return new GatewayResponse(409, null, &amp;quot;fail&amp;quot;);
   }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;
    
    &lt;p&gt;That's all the code changes we need to make in Spring Boot version 2 versus Spring Boot 3. For Spring Boot Version 2, all dependencies will be the same.&lt;/p&gt; &lt;br/&gt;
    
    &lt;p&gt;Simply use the Spring Cloud version that is compatible with Spring Boot version 2.&lt;/p&gt; &lt;br/&gt;
    
    &lt;h3&gt;Changes to the AWS lambda handler for Spring Boot version 2&lt;/h3&gt;
    
    &lt;p&gt;The deployment to the AWS lambda function is identical to what we described earlier in this guide for Spring Boot version 3.
&lt;/p&gt; &lt;br/&gt;
    
    &lt;p&gt;However, because we changed the code, we must configure the class's handler.&lt;/p&gt; &lt;br/&gt;
    
    &lt;p&gt;We created a handler called RequestHandler class. As a result, we have to provide the absolute path of a package of this class in the AWS Lambda Function's handler configuration.&lt;/p&gt;&lt;br/&gt;
    
    &lt;blockquote&gt;in.learnjavaskills.springcloudfunctionawslambda.handler.RequestHandler&lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt;
    
    &lt;p&gt;I've already deployed the Spring Boot version 2 (Spring Cloud function), and you may edit the handler setting by navigating to the function's runtime settings, as seen in the image below.&lt;/p&gt; &lt;br/&gt;
    
    &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii8aigQiJqkY8pHZOgE8pRVlD2fJM4KbJ3N7BiU8I-SugxoJrfqnjEgWYz6mt8hOUDbj-QrsT8tnh8TVtmA2KCK_NLraT6syUz2TQi3g31-avU5gqPCPv8YGl47EdvsBkGwv8-4o5GMJ22Ek9TvuAzCsPkKZ5ikBVo3Ml_bTVZ8uUxEcVnBAcT2isWWrql/s1600/spring-boot-version-2.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="spring boot version 2 spring cloud function aws lambda dashboad" border="0" data-original-height="513" data-original-width="1237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii8aigQiJqkY8pHZOgE8pRVlD2fJM4KbJ3N7BiU8I-SugxoJrfqnjEgWYz6mt8hOUDbj-QrsT8tnh8TVtmA2KCK_NLraT6syUz2TQi3g31-avU5gqPCPv8YGl47EdvsBkGwv8-4o5GMJ22Ek9TvuAzCsPkKZ5ikBVo3Ml_bTVZ8uUxEcVnBAcT2isWWrql/s1600/spring-boot-version-2.png"/&gt;&lt;/a&gt;&lt;/div&gt;
    
    &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEie6fyjPLRJn8jc8uA8GW5sRRJI4BZ1SExnZdDWyaVqgY1GuwAGFjsOYD3uz0523LsNjt51Ky0wfHDLLLTeeFDdHS4d_UjdQTptYlZ4C3IrIAjR3SUVA9uTzqQ7KKIJMMa_-6l6h68AZeqfOAA7vnXGzGnbFxIBy7AkoEEgJw1-dfvjRwBWDqvzE7PDjkX3/s1600/spring-boot-version-2-handler.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="aws handler setting" border="0" data-original-height="546" data-original-width="841" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEie6fyjPLRJn8jc8uA8GW5sRRJI4BZ1SExnZdDWyaVqgY1GuwAGFjsOYD3uz0523LsNjt51Ky0wfHDLLLTeeFDdHS4d_UjdQTptYlZ4C3IrIAjR3SUVA9uTzqQ7KKIJMMa_-6l6h68AZeqfOAA7vnXGzGnbFxIBy7AkoEEgJw1-dfvjRwBWDqvzE7PDjkX3/s1600/spring-boot-version-2-handler.png"/&gt;&lt;/a&gt;&lt;/div&gt;
      
  &lt;/div&gt;
  
  
  &lt;div&gt;
    &lt;h2&gt;Conclussion&lt;/h2&gt;
    &lt;hr&gt;
    
    &lt;p&gt;In this course, we learned how to create a spring cloud function and run it on our local system. In Spring Boot Versions 2 and 3, we learn how to develop a spring cloud function and deploy it to AWS Lambda.&lt;/p&gt; &lt;br/&gt;
    
    &lt;p&gt;We not only built the spring cloud function, but we also saw how to deploy it into the AWS lambda function. We'll look at the layer in the AWS lambda function and how to use it.&lt;/p&gt;&lt;br/&gt;
    
    &lt;p&gt;We also built a Rest API by triggering our AWS lambda function through the API gateway.&lt;/p&gt;
    
     &lt;blockquote&gt;Once you've finished your lab exercise, remember to delete your AWS lambda function, layer, and API Gateway.(alert-error)&lt;/blockquote&gt; &lt;br/&gt;
    
     &lt;p&gt;Keep learning and keep growing.&lt;/p&gt;
    
  &lt;/div&gt;  
  




</content><link href="https://www.learnjavaskills.in/feeds/5210293520487903286/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/09/spring-cloud-function-deploys-in-aws-lambda-and-triggers-using-the-api-gateway.html#comment-form" rel="replies" title="1 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/5210293520487903286" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/5210293520487903286" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/09/spring-cloud-function-deploys-in-aws-lambda-and-triggers-using-the-api-gateway.html" rel="alternate" title="How to create serverless function with spring cloud function, deploy into AWS Lambda and expose rest endpoint using AWS API Gateway | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcTTTL7U8TAoqQLe5dzWJifdPvgeTGs51-CTSs1tqFDPXoSqFcZIwWfPIiSQNl9Y2K7LcJq444w3hxY02SV-Qm6_z9EwOQzu7khpBCR4w5qrn6ZEP7WJJXhBREDkvR3Yd_LJ99Oquj9ZHIVt-n39ij2FWLIVtMel5P-9rk0yug68I3uJJcbZ8gxJGuCUbZ/s72-c/serverless%20function%20logo%202.png" width="72"/><thr:total>1</thr:total><georss:featurename>United States</georss:featurename><georss:point>37.09024 -95.712891</georss:point><georss:box>8.780006163821156 -130.869141 65.400473836178847 -60.556641</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-188111118090024406</id><published>2024-03-03T15:14:00.000+05:30</published><updated>2024-03-03T15:14:02.924+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="Spring Data JPA"/><title type="text">How to use SpEL (Spring Expression Language) in the Spring Data JPA</title><content type="html">&lt;!-- Introduction --&gt;
&lt;div&gt;
  &lt;p&gt;An expression language is used to query and operate on the objects at runtime. In Java, several expression languages are available to use, such as &lt;a href = "https://docs.jboss.org/seam/2.3.1.Final/reference/html/elenhancements.html" target="_blank" rel="nofollow"&gt;JBoss EL&lt;/a&gt;, &lt;a href = "https://en.wikipedia.org/wiki/MVEL" target="_blank" rel="nofollow"&gt;MVFLEX Expression Language (MVEL)&lt;/a&gt;,Object-Graph Navigation Language (ONGL) etc.&lt;/p&gt; &lt;br/&gt;

  &lt;p&gt;In this article, we will have some hands-on SpEL (Spring Expression Language), and I will walk you through how to use SpEL in the Spring Data JPA &lt;code&gt;@Query&lt;/code&gt; annotation.&lt;/p&gt;
&lt;/div&gt; &lt;br/&gt;

&lt;strike&gt;toc&lt;/strike&gt;

&lt;br/&gt;


&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWWchpc_Z0nrRGePEPVVMXBaWL910L941Zur8CTnEfXIyH6dS5wAvH7iIMnirVayxB3TefhEasFxrWYInZKE8aPulBARwF1-sZpSRz-fD9WJXdAtn0XL-AMmYLsoE8hDjNYdnL0zuMiLFiZvUEqhWLfcJYbQtK7X858YRI0E2G6mA-_6v2U-mN0ZXKjbx-/s1600/2.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="How to use SpEL (Spring Expression Language) in the Spring Data JPA thumbnail" border="0" data-original-height="720" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWWchpc_Z0nrRGePEPVVMXBaWL910L941Zur8CTnEfXIyH6dS5wAvH7iIMnirVayxB3TefhEasFxrWYInZKE8aPulBARwF1-sZpSRz-fD9WJXdAtn0XL-AMmYLsoE8hDjNYdnL0zuMiLFiZvUEqhWLfcJYbQtK7X858YRI0E2G6mA-_6v2U-mN0ZXKjbx-/s1600/2.png"/&gt;&lt;/a&gt;&lt;/div&gt;


&lt;!-- Image thumbnail --&gt;
&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/a/AVvXsEhGuE_rsPjOZ1_0ltsoWc_fbjUaAOUZ1pMSP9VSCp7W5r7qUmYLWbn8C-SxOOoLIB6QX7x5Hnywa_QZBXoSWJWU3i4totK5d61l88hFhPjflJU9LNCY3Ycb2SqIPEMhdwKB5nXuROm5puCAF0ls1qT-aGCDqqBFDExwUEAkjo3VfxRnFOGhUIFqdAh1vQ" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="How to use SpEL (Spring Expression Language) in the Spring Data JPA thumbnail" border="0" data-original-height="900" data-original-width="1600" src="https://blogger.googleusercontent.com/img/a/AVvXsEhGuE_rsPjOZ1_0ltsoWc_fbjUaAOUZ1pMSP9VSCp7W5r7qUmYLWbn8C-SxOOoLIB6QX7x5Hnywa_QZBXoSWJWU3i4totK5d61l88hFhPjflJU9LNCY3Ycb2SqIPEMhdwKB5nXuROm5puCAF0ls1qT-aGCDqqBFDExwUEAkjo3VfxRnFOGhUIFqdAh1vQ" hidden/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;!-- SpEL in the Spring Data JPA --&gt;
&lt;div&gt;
	&lt;h2&gt;SpEL in the Spring Data JPA&lt;/h2&gt;
  	&lt;hr&gt;
  
  &lt;p&gt;The Spring Data Jpa enables us to manually bind the parameters using the &lt;code&gt;@Query&lt;/code&gt; annotation and this  &lt;code&gt;@Query&lt;/code&gt; annotation is also capable of binding the dynamic parameters using the SpEL (Spring Express Language).&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;There are a couple of approaches to hook the SpEL parameter in the Spring Data JPA repository methods. It can be an &lt;b&gt;index base entry&lt;/b&gt; or a &lt;b&gt;named parameter utilizing the &lt;code&gt;@Param&lt;/code&gt; annotation&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;
  
  &lt;h3&gt;Index approach&lt;/h3&gt;
  &lt;p&gt;In this approach, we hook the parameters using the indexes of the method argument. The following is a simple example of SpEL in the Spring data Jpa used as the index of the method argument.&lt;/p&gt;
  
  &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; @Query(&amp;quot;FROM BookEntity WHERE uniqueCode = ?#{[0]} AND title = ?#{[1]}&amp;quot;)
 List&amp;lt;BookEntity&amp;gt; findBookByUniqueBookCode(String uniqueCode, String title); &lt;/code&gt;&lt;/pre&gt; 
  
  &lt;br/&gt;
  
  &lt;h3&gt;Using the named parameter in the @Param annotation&lt;/h3&gt;
  &lt;p&gt;The SpEL(Spring Expression Language) can be binded using the &lt;code&gt;@Param&lt;/code&gt; annotation to the &lt;code&gt;@Query&lt;/code&gt;. The &lt;code&gt;@Param&lt;/code&gt; annotation expects the value argument. The SpEL declared using the @Param annotation is shown below.&lt;/p&gt;
  &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; @Query(&amp;quot;FROM BookEntity WHERE uniqueCode = ?#{#uniqueCode} AND title = ?#{#title}&amp;quot;)
 List&amp;lt;BookEntity&amp;gt; findBookByUniqueBookCode1(@Param(&amp;quot;uniqueCode&amp;quot;) String uniqueCode, @Param(&amp;quot;title&amp;quot;) String title);&lt;/code&gt;&lt;/pre&gt;
  
&lt;/div&gt;

&lt;br&gt;

&lt;div&gt;
  &lt;h2&gt;Various patterns of initiating SpEL (Spring Expression Language)&lt;/h2&gt;
  &lt;hr&gt;
  &lt;p&gt;The Spring Data JPA provides two patterns to bind the SpEL parameters in the &lt;code&gt;@Query&lt;/code&gt; annotation. The &lt;b&gt;?#&lt;/b&gt; or &lt;b&gt;:#&lt;/b&gt; can be used to activate the SpEL binding.&lt;/p&gt; &lt;br/&gt;
  &lt;p&gt;We looked at how to bind the SpEL parameters using the &lt;b&gt;?#&lt;/b&gt;. I prefer the second syntax, which is &lt;b&gt;:#&lt;/b&gt;. In the subsequent examples, I will lead you how to use &lt;b&gt;:#&lt;/b&gt;.&lt;p&gt; &lt;br/&gt;
&lt;/div&gt;

&lt;br&gt;


&lt;div&gt;
	&lt;h2&gt;The SpEL (Spring Expression Language) utilizing the entity class.&lt;/h2&gt; 
  	&lt;hr&gt;
  	&lt;p&gt;Are you wondering if we can use named parmaters using the @param annotion without using SpEL and this will work perfectly fine? Then why should I use SpEL?&lt;/p&gt; &lt;br/&gt;
  	&lt;p&gt;Correct. The real joy of using SpEL is with the entity class. Allow me to present to you how we can take advantage of the SpEL using the entity classes. The below snippet utilises the enity in the method argument.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; @Query(&amp;quot;SELECT price FROM BookEntity where uniqueCode = :#{#bookEntity.uniqueCode}&amp;quot;)
 List&amp;lt;Double&amp;gt; findBookPriceByUniqueCode(@Param(&amp;quot;bookEntity&amp;quot;) BookEntity bookEntity); &lt;/code&gt;&lt;/pre&gt;
  
  &lt;br&gt;
  
  &lt;p&gt;I have set only the uniqueCode parameter in the BookEnity because I only require the uniqueCode parameter in the query. You can configure the entity parameters to meet your conditions.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java"&gt; BookEntity bookEntity = BookEntity.builder()
	.uniqueCode("BK0001")
	.build(); 
 List&lt;Double&gt; bookPriceByUniqueCode = bookRepository.findBookPriceByUniqueCode(bookEntity);&lt;/code&gt;&lt;/pre&gt;
  
  &lt;br&gt;
  
  &lt;h3&gt;The SpEL (Spring Expression Language) with the relationship entity&lt;/h3&gt;
  &lt;p&gt;We frequently work with relational databases, and we may be required to add entities within entities in order to map the associations in Hibernate.&lt;/p&gt; &lt;br/&gt;
  &lt;p&gt;If you are wondering, can we take benefit of SpEL while using the relationship hibernate mapping? The response will be yes, we can take total advantage of  the SpEL in the hibernate mapping entity as well.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; @Query(&amp;quot;FROM BookEntity WHERE authorEntity = :#{#bookEntity.authorEntity}&amp;quot;)
 List&amp;lt;BookEntity&amp;gt; findBooksByAuthor(@Param(&amp;quot;bookEntity&amp;quot;) BookEntity bookEntity); &lt;/code&gt;&lt;/pre&gt; 
  
  &lt;br&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; AuthorEntity authorEntity = AuthorEntity.builder()
	.authorId(1)
	.build();
 BookEntity bookEntity = BookEntity.builder()
	.authorEntity(authorEntity)
	.build(); 
 List&lt;BookEntity&gt; findBooksByAuthor = bookRepository.findBooksByAuthor(bookEntity);&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;
&lt;/div&gt; 

&lt;br&gt;


&lt;div&gt;
  	&lt;h2&gt;Summary&lt;/h2&gt;
    &lt;hr&gt;
	&lt;p&gt;In this tutorial, we learned about expression language and how to utilize SpEL (Spring Express Language) in the Spring Data JPA @Query. and We saw various patterns for binding the parameters in the SpEL and multiple ways to access them in the Spring Data JPA.&lt;/p&gt;  &lt;br/&gt;
  
  &lt;p&gt;If you are curious to read the source code, you can find it &lt;a href = "https://github.com/LearnJavaSkills/spel-in-springdatajpa" target="_blank" rel="nofollow"&gt;here&lt;/a&gt;.&lt;p&gt;
  &lt;br/&gt;
  
  &lt;p&gt;Keep learning and keep growing.&lt;/p&gt;
  
  &lt;p align="right"&gt;&lt;a href="https://www.learnjavaskills.in/2022/01/configure-multiple-databases-in-spring-data-jpa.html"&gt;(getButton) #text=(Next: Configure Multiple Databases in Spring Data JPA) #icon=(link) #color=(#2339bd)&lt;/a&gt;&lt;/p&gt;

  
&lt;/div&gt;
</content><link href="https://www.learnjavaskills.in/feeds/188111118090024406/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2022/02/spring-expression-language-in-spring-data-jpa.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/188111118090024406" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/188111118090024406" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2022/02/spring-expression-language-in-spring-data-jpa.html" rel="alternate" title="How to use SpEL (Spring Expression Language) in the Spring Data JPA" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWWchpc_Z0nrRGePEPVVMXBaWL910L941Zur8CTnEfXIyH6dS5wAvH7iIMnirVayxB3TefhEasFxrWYInZKE8aPulBARwF1-sZpSRz-fD9WJXdAtn0XL-AMmYLsoE8hDjNYdnL0zuMiLFiZvUEqhWLfcJYbQtK7X858YRI0E2G6mA-_6v2U-mN0ZXKjbx-/s72-c/2.png" width="72"/><thr:total>0</thr:total><georss:featurename>India</georss:featurename><georss:point>20.593684 78.96288</georss:point><georss:box>-7.7165498361788458 43.80663 48.903917836178849 114.11913</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-4074884498498189587</id><published>2024-03-03T15:13:00.004+05:30</published><updated>2024-03-03T15:13:53.863+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="Spring Data JPA"/><title type="text">Spring Data JPA DTO Projections | Learn Java Skills</title><content type="html">
  
&lt;p&gt;The term projection means wrapping/projecting the data into the object. There are three types of widely projection used in the Spring Data JPA. &lt;/p&gt;&lt;br/&gt;

&lt;p&gt;In the Spring Data JPA bydefault scaler projection is enabled. In this tutorial, we will learn how to use the DTO projection in the Spring Boot application using the Spring Data JPA.&lt;/p&gt;

&lt;br/&gt;


1. Scaler projection &lt;br/&gt;
2. Interface projection &lt;br/&gt;
3. DTO projection &lt;br/&gt;



&lt;br/&gt;

&lt;strike&gt;toc&lt;/strike&gt;


&lt;br/&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyrnKafinZa_vjxNCoPNIsmgP7qhalpn_reAEf_AdEqUNNCeqoucOeACA_YXiDLp-K5F16u2EYwxo-jMTdgCvDyw07XGIrPPPte04v9lSZTuFkkCLrT1oddn65UOQr8OF4ozlKTGw31LDM-Jy1BF5HtY-EyhUU3RGAzjH4NFvgOvR9I4uu7ckWpSmX4pdm/s1600/Spring%20Data%20JPA%20DTO%20Projections_thumbnail.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Spring Data JPA DTO Projections thumbnail" border="0" data-original-height="720" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyrnKafinZa_vjxNCoPNIsmgP7qhalpn_reAEf_AdEqUNNCeqoucOeACA_YXiDLp-K5F16u2EYwxo-jMTdgCvDyw07XGIrPPPte04v9lSZTuFkkCLrT1oddn65UOQr8OF4ozlKTGw31LDM-Jy1BF5HtY-EyhUU3RGAzjH4NFvgOvR9I4uu7ckWpSmX4pdm/s1600/Spring%20Data%20JPA%20DTO%20Projections_thumbnail.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOvCaoH0FzOh_6zvskoVAAOKvu9DRla_6wW9J0IT8S0f8pvOFAMWXO7nkFtVHMdRrb0uEQGBYEDpBebGZpOVIjOQlnSR9qmsF70S6uxv5OgPubfBQryO7jBqjFZlim_hvx7n-u3mcao2_qeMWsMVdqiaKoTfdiS80cm1m9KZvuurVmoM2IZ0FG3omLDzNA/s1600/Spring%20Data%20JPA%20DTO%20Projections.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="c" border="0" data-original-height="900" data-original-width="1600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOvCaoH0FzOh_6zvskoVAAOKvu9DRla_6wW9J0IT8S0f8pvOFAMWXO7nkFtVHMdRrb0uEQGBYEDpBebGZpOVIjOQlnSR9qmsF70S6uxv5OgPubfBQryO7jBqjFZlim_hvx7n-u3mcao2_qeMWsMVdqiaKoTfdiS80cm1m9KZvuurVmoM2IZ0FG3omLDzNA/s1600/Spring%20Data%20JPA%20DTO%20Projections.png" hidden/&gt;&lt;/a&gt;&lt;/div&gt;


&lt;h2&gt;DTO projection in the entity &lt;/h2&gt;
&lt;hr&gt;
  
&lt;p&gt; We can use DTO projection on an entity to map the selected parameter to the entity class in the spring data JPA. &lt;/p&gt;&lt;br/&gt;

&lt;p&gt; Let's suppose we have a table called &lt;code&gt;books&lt;/code&gt; with the following columns, and we want to select only selected columns such as &lt;b&gt;title&lt;/b&gt;, &lt;b&gt;price&lt;/b&gt;, and &lt;b&gt;unit_sold&lt;/b&gt;. &lt;/p&gt; &lt;br/&gt;

&lt;p&gt;In such scenario, we can use the DTO projection on an entity to map the selected paramter into the entity; although you can use the &lt;code&gt;findAll()&lt;/code&gt; method of the JPARepository interface, which maps the column into the entity, that could not be the best practice if you are required to select only the selected column. &lt;p&gt; &lt;br/&gt;
  
&lt;p&gt; On the following table, We will use the DTO projection. &lt;p&gt; 

&lt;br/&gt;

&lt;pre&gt;&lt;code class = "sql:brush"&gt; create table books(
   id bigint(20) not null auto_increment primary key,
   title varchar(255) not null,
   price float(3,2) not null,
   unit_sold bigint(200),
   author_id bigint not null,
   FOREIGN KEY (author_id) REFERENCES author(id)
 ); &lt;/code&gt; &lt;/pre&gt;

  
&lt;h3&gt;First Create the Entity &lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java:brush"&gt; public class Books
 {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    private String title;
    private BigDecimal price;
    private long unitSold;
    @ManyToOne()
    @JoinColumn(name = &amp;quot;author_id&amp;quot;, referencedColumnName = &amp;quot;id&amp;quot;)
    private Author author;
	//Getter &amp;amp; Setter
 } &lt;/code&gt;&lt;/pre&gt;

&lt;br/&gt;

&lt;h3&gt;Constructor using parameters&lt;/h3&gt;

&lt;p&gt;Once we have completed creating the entity, we need to create the constructor with only the required parameters that we wish to fetch from the table. In our case, we like to fetch the &lt;u&gt;title, price, and unit_sold&lt;/u&gt;. &lt;/p&gt; &lt;br/&gt;

&lt;p&gt; In the &lt;code&gt;Books&lt;/code&gt; Entity, Create the constructor using the desire parameter just like in the below code. &lt;/p&gt; 

&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java:brush"&gt; public Books(String title, BigDecimal price, long unitSold)
 {
    this.title = title;
    this.price = price;
    this.unitSold = unitSold;
 } &lt;/code&gt;&lt;/pre&gt;

&lt;br/&gt;


&lt;h3&gt;JPA Query for Entity DTO projection &lt;/h3&gt;

&lt;p&gt; Let's create a JPA select query that will map the table output into the Entity. We will be using the Books constructor in the JPA query, which we created in the earlier step. &lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java:brush"&gt; @Query(&amp;quot;select new Books(title, price, unitSold) from Books&amp;quot;)
 List&amp;lt;Books&amp;gt; findAllBooks(); &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt; 

&lt;p&gt;You can observe that &lt;code&gt;new Books(title, price, unitSold)&lt;/code&gt; is nothing but the constructor that we created in the previous step. This constructor will map the select query output from the table into the entity class. &lt;/p&gt;  &lt;br/&gt;
 
&lt;h3&gt;Test Entity DTO Projection &lt;/h3&gt;

  &lt;pre&gt;&lt;code class = "java:brush"&gt; @Test
 void findAllBooksTest() 
 {
   List&amp;lt;Books&amp;gt; allBooks = booksRepository.findAllBooks();
   System.out.println(allBooks);
 }&lt;/code&gt;&lt;/pre&gt;
    
    
    
    &lt;br/&gt;
  
&lt;p&gt;Hibernate will execute the below query internally to replace the DTO projection JPA query with the SQL query. &lt;/p&gt;&lt;br/&gt;
  
&lt;pre&gt;&lt;code class = "sql:brush"&gt; Hibernate: 
    select
        b1_0.title,
        b1_0.price,
        b1_0.unit_sold 
    from
        books b1_0 &lt;/code&gt;&lt;/pre&gt;
  
  &lt;br/&gt;
  
&lt;p&gt;Below is the output of the &lt;code&gt;findAllBooks()&lt;/code&gt; method. As you can see, we found values of the &lt;b&gt;title&lt;/b&gt;, &lt;b&gt;price&lt;/b&gt;, and &lt;b&gt;unit_sold&lt;/b&gt; columns only, and id and author_is were null because we didn't fetch those parameters in our DTO projection query in the repository.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "txt:brush"&gt; Books list are : 
[Books{id=0, title='Harry Potter', price=1.1, unitSold=2000, author=null}] &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;
  
  
&lt;h2&gt;DTO Projection on join query &lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Till now, we have learnt how to use DTO projection in the one entity itself, Let's now take a glimpse how we can leverage the DTO projection technique in the join query as well. &lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Let's create two tables such as &lt;code&gt;books&lt;/code&gt; and the &lt;code&gt;author&lt;/code&gt;, and we will use an &lt;b&gt;inner join query to fetch some selected parameter&lt;/b&gt; and will map those parameters into the DTO.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "sql:brush"&gt; create table books(
   id bigint(20) not null auto_increment primary key,
   title varchar(255) not null,
   price float(3,2) not null,
   unit_sold bigint(200),
   author_id bigint not null,
   FOREIGN KEY (author_id) REFERENCES author(id)
 ); &lt;/code&gt; &lt;/pre&gt; 


&lt;pre&gt;&lt;code class = "sql:brush"&gt; create table author(
   id bigint not null auto_increment primary key,
   name varchar(255) not null
 ); &lt;/code&gt; &lt;/pre&gt; 


&lt;p&gt;Let's create one DTO with the elements which we desire to fetch with the constructor.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java:brush"&gt; public class BooksWithAuthorDTO
 {
    private String bookTitle;
    private long bookPrice;
    private BigDecimal bookUnitSold;
    private String authorName;
	//Getter and Setter
    
    public BooksWithAuthorDTO(String bookTitle, long bookPrice, BigDecimal bookUnitSold, String authorName)
    {
        this.bookTitle = bookTitle;
        this.bookPrice = bookPrice;
        this.bookUnitSold = bookUnitSold;
        this.authorName = authorName;
    }
 }&lt;/code&gt;&lt;/pre&gt; 

&lt;br/&gt;


&lt;p&gt;Before we begin, First we need to learn about two annotations which are &lt;code&gt;@NamedNativeQuery&lt;/code&gt; and &lt;code&gt;@SqlResultSetMapping&lt;/code&gt; &lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;@NamedNativeQuery annotation &lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;@NamedNativeQuery&lt;/code&gt; annotation is the entity level annotation and its use to create the name SQL query in the JPQL and as well as the native query.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The name should be the unique across the persistence unit because this name will be used in the JPA repository method to fetch the data. &lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java/brush"&gt; @NamedNativeQueries(
  @NamedNativeQuery(name = &amp;quot;Books.findBooksWithAuthor&amp;quot;,
    query = &amp;quot;select b.title as bookTitle, b.price as bookPrice, &amp;quot; +
      &amp;quot;b.unit_sold as bookUnitSold, a.name as authorName &amp;quot; +
      &amp;quot;from books b left join author a on b.author_id = a.id;&amp;quot;,
    resultSetMapping = &amp;quot;Mapping.BooksWithAuthorMapping&amp;quot;
  )
) &lt;/code&gt; &lt;/pre&gt;

&lt;p&gt;Make sure you use an alias name the same as the DTO class parameter name.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;@SqlResultSetMapping annotation &lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;@SqlResultSetMapping&lt;/code&gt; annotation is also the entity level annotation. As the name of this annotation, this annotation is used to map the SQL query output into the DTO class using the constructs and instruction the parameter type to parse the correct data type into the DTO.&lt;/p&gt;

&lt;br/&gt;


&lt;pre&gt;&lt;code class = "java/brush"&gt; @SqlResultSetMapping(name = &amp;quot;Mapping.BooksWithAuthorMapping&amp;quot;,
  classes = @ConstructorResult(targetClass = BooksWithAuthorDTO.class,
    columns = {
      @ColumnResult(name = &amp;quot;bookTitle&amp;quot;),
      @ColumnResult(name = &amp;quot;bookPrice&amp;quot;, type = Long.class),
      @ColumnResult(name = &amp;quot;bookUnitSold&amp;quot;, type = BigDecimal.class),
      @ColumnResult(name = &amp;quot;authorName&amp;quot;)
    })
 ) &lt;/code&gt; &lt;/pre&gt;


&lt;h3&gt;@ConstructorResult annotaion&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;@ConstructorResult&lt;/code&gt; annotation will specify the DTO class in which output of the SQL query should mapped, This annotation accepts two parameters such as &lt;b&gt;targetClass&lt;/b&gt; and &lt;b&gt;columns&lt;/b&gt; &lt;/p&gt; &lt;br/&gt;

&lt;p&gt;In the &lt;code&gt;targetClass&lt;/code&gt; parameter we need to declare the DTO class, and under the &lt;u&gt;columns&lt;/u&gt; we need to instruct how to use contractions to map the SQL output into the parameter using the &lt;code&gt;@ColumnResult&lt;/code&gt; &lt;/p&gt; &lt;br/&gt; 

&lt;p&gt;If you have thoroughly monitored the &lt;u&gt;@ColumnResult&lt;/u&gt;, It's anticipate the &lt;b&gt;name&lt;/b&gt; and the &lt;b&gt;type&lt;/b&gt; parameter, in the &lt;code&gt;name&lt;/code&gt; we have to declare the DTO class parameter and under the &lt;code&gt;type&lt;/code&gt; we need to render the data type of those parameters.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&lt;b&gt;String data type is bydefualt&lt;/b&gt; hence, we don't need to explicitly declare that but for the other data type we required the appropriate data type to mapped to the fields.&lt;/p&gt;
 &lt;br/&gt;

&lt;h3&gt;JPA Rpository method &lt;/h3&gt;

&lt;p&gt;Now, Create a method in the &lt;b&gt;Books&lt;/b&gt; Repository with the name which we used in the &lt;code&gt;@NamedNativeQueries&lt;/code&gt;. In our case, it's &lt;code&gt;findBooksWithAuthor()&lt;/code&gt;. &lt;/p&gt;&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java:brush"&gt; @Query(nativeQuery = true)
 List&amp;lt;BooksWithAuthorDTO&amp;gt; findBooksWithAuthor(); &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;Test DTO projection with join query &lt;/h3&gt;

&lt;pre&gt;&lt;code class = "java:brush"&gt; @Test
 void findBooksWithAuthorTest()
 {
    List&amp;lt;BooksWithAuthorDTO&amp;gt; booksWithAuthor = booksRepository.findBooksWithAuthor();
	System.out.println(&amp;quot;Books with author are : &amp;quot;);
	System.out.println(booksWithAuthor);
 } &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;p&gt;Hibernate will execute the below query internally to replace the DTO projection JPA query with the SQL query.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "sql/brush"&gt; Hibernate: 
    select
        b.title as bookTitle,
        b.price as bookPrice,
        b.unit_sold as bookUnitSold,
        a.name as authorName 
    from
        books b 
    left join
        author a 
            on b.author_id = a.id; &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;


&lt;p&gt;Output of the above query which has been mapped to the DTO.&lt;/p&gt;

&lt;br/&gt;

&lt;pre&gt;&lt;code class = "java:brush"&gt; Books with author are : 
[BooksWithAuthorDTO{bookTitle=&amp;#39;Harry Potter&amp;#39;, bookPrice=1, bookUnitSold=2000, authorName=&amp;#39;J.K. Rowling&amp;#39;}] &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt; Conclusion &lt;/h2&gt;

&lt;p&gt;Using the DTO projection in the join query is very handy and it's leverage the advantages over the scalar projection because in the scalar projection we explicitly need to convert the Object data type into the airport data type before we need to consume it. &lt;/p&gt; 
&lt;br/&gt;
&lt;p&gt;DTO projection enhances the code's readability and provides more flexible or easily modifiable code.&lt;/p&gt;

&lt;p&gt;Keep learning and keep growing.&lt;/p&gt;

&lt;p align="right"&gt;&lt;a href="https://www.learnjavaskills.in/2022/02/spring-expression-language-in-spring-data-jpa.html"&gt;(getButton) #text=(Next: Spring Expression Language in Spring Data JPA) #icon=(link) #color=(#2339bd)&lt;/a&gt;&lt;/p&gt;

 </content><link href="https://www.learnjavaskills.in/feeds/4074884498498189587/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/08/spring-data-jpa-dto-projections.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/4074884498498189587" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/4074884498498189587" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/08/spring-data-jpa-dto-projections.html" rel="alternate" title="Spring Data JPA DTO Projections | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyrnKafinZa_vjxNCoPNIsmgP7qhalpn_reAEf_AdEqUNNCeqoucOeACA_YXiDLp-K5F16u2EYwxo-jMTdgCvDyw07XGIrPPPte04v9lSZTuFkkCLrT1oddn65UOQr8OF4ozlKTGw31LDM-Jy1BF5HtY-EyhUU3RGAzjH4NFvgOvR9I4uu7ckWpSmX4pdm/s72-c/Spring%20Data%20JPA%20DTO%20Projections_thumbnail.png" width="72"/><thr:total>0</thr:total><georss:featurename>Mumbai, Maharashtra, India</georss:featurename><georss:point>19.0759837 72.8776559</georss:point><georss:box>-9.2342501361788472 37.721405899999993 47.386217536178847 108.0339059</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-3512974457851572748</id><published>2024-03-03T15:13:00.003+05:30</published><updated>2024-03-03T15:13:44.661+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">Open Feign Client | How to Consume Rest API in Spring Cloud or Spring Boot | Learn Java Skills</title><content type="html">&lt;!-- Introduction --&gt;
&lt;div&gt;
    &lt;p&gt;There are many libraries available for Java to consume restful web services, and in the spring boot, Java developers mostly favor the Rest Template to consume the APIs. No doubt, the Rest Template is absolutely acceptable to use in an enterprise Java application. &lt;/p&gt; &lt;br/&gt;
  &lt;p&gt;&lt;b&gt;The RestTemplate required us to write more code, and  the more lines of code you write, the more bugs may live in your application&lt;/b&gt;. What if I tell you you can get rid of most of the boilerplate code of RestTemplate to consume the API? &lt;/p&gt; &lt;br/&gt;
   &lt;p&gt;Yes, you read correctly. We can use the Open Feign client to consume the Rest APIs in the Spring Boot applications. &lt;/p&gt; &lt;br/&gt;
  &lt;p&gt;If you are a Java developer and you are using the Rest Template in your Spring Boot application and you are curious to explore some more libraries to consume the Rest APIs, then you have landed in the correct article. &lt;/p&gt; &lt;br/&gt;
  &lt;p&gt;In this article, I'm going to walk you through how to use an &lt;b&gt;open-feign client to consume the APIs in the Spring Boot application&lt;/b&gt;, and I can ensure that you can gain a lot of confidence from this article to use in your next production-ready code.&lt;/p&gt;
&lt;/div&gt;


&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidFHI02qdDwj3srTpCrn2GgsDxzKUnUGakRsQzlAKYh-rpa7_0SkNShRtWoEcVETqn5bEp9KyKNXdGZtM5BKlYOFk_SeGwzFp-ySsajDYZzQ0UWvL8eO5n0-VD7UO7ZNluZYh7l4FlBHSQ0mEd1airNsynQ5WqBmGCzRYVgeUjWVPOq-9GSRkLsp6HeXO-/s1600/open%20feign%20client%20final%20thumbnail.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Feign Client | Open Feign | How to Consume Rest API in Spring Cloud or Spring Boot | Learn Java Skills thumbnail image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidFHI02qdDwj3srTpCrn2GgsDxzKUnUGakRsQzlAKYh-rpa7_0SkNShRtWoEcVETqn5bEp9KyKNXdGZtM5BKlYOFk_SeGwzFp-ySsajDYZzQ0UWvL8eO5n0-VD7UO7ZNluZYh7l4FlBHSQ0mEd1airNsynQ5WqBmGCzRYVgeUjWVPOq-9GSRkLsp6HeXO-/s1600/open%20feign%20client%20final%20thumbnail.png"/&gt;&lt;/a&gt;&lt;/div&gt;


&lt;strike&gt;toc&lt;/strike&gt;


&lt;!-- Overview of the Feign Client --&gt;
&lt;div&gt;
  &lt;h2&gt;What is Open Feign Client, and why should you use it in your next project? &lt;/h2&gt;
  &lt;hr&gt;
  
Open-Feign-Client is a library to consume the Rest APIs. Open-Feign-Client comes under the umbrella of the Spring Cloud project. Some of the advantages of open feign clients are listed below. 
  &lt;ul&gt;
  &lt;li&gt;Open Feign Cleint is widely used in the Java-based Spring Boot microservice architecture. It provides the load balancing feature out of the box by just implementing the service registry. &lt;/li&gt;
    &lt;li&gt; The URL and the port can be dynamically fetched from the service registry. &lt;/li&gt;
    &lt;li&gt;Only create abstract methods to consume the APIs.&lt;/li&gt;
  &lt;/ul&gt;

&lt;/div&gt;


&lt;!-- Dependencies are required to use the open feign client --&gt;
&lt;div&gt;
  &lt;h2&gt;Dependencies are required to use the Open Feign Client&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;h3&gt;Maven openfeign dependency &lt;/h3&gt;
  &lt;pre&gt;&lt;code class = "xml:brush"&gt; &amp;#x3C;dependency&amp;#x3E;
    &amp;#x3C;groupId&amp;#x3E;org.springframework.cloud&amp;#x3C;/groupId&amp;#x3E;
    &amp;#x3C;artifactId&amp;#x3E;spring-cloud-starter-openfeign&amp;#x3C;/artifactId&amp;#x3E;
 &amp;#x3C;/dependency&amp;#x3E; &lt;/code&gt; &lt;/pre&gt;
  
  &lt;h3&gt;Maven Spring cloud dependency &lt;/h3&gt;
  &lt;pre&gt;&lt;code class = "xml:brush"&gt; &amp;lt;dependencyManagement&amp;gt;
   &amp;lt;dependencies&amp;gt;
      &amp;lt;dependency&amp;gt;
	    &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
	    &amp;lt;artifactId&amp;gt;spring-cloud-dependencies&amp;lt;/artifactId&amp;gt;
	    &amp;lt;version&amp;gt;${spring-cloud.version}&amp;lt;/version&amp;gt;
	    &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
	    &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
	&amp;lt;/dependency&amp;gt;
   &amp;lt;/dependencies&amp;gt;
 &amp;lt;/dependencyManagement&amp;gt;&lt;/code&gt; &lt;/pre&gt;
  
	&lt;p&gt;You can find the lates version of above dependencies from &lt;a href= "https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign/4.0.4"&gt;here&lt;/a&gt;  
      
&lt;/div&gt;

&lt;br/&gt;

&lt;div&gt;
 
  &lt;h2&gt;Annotations &lt;/h2&gt;
  &lt;hr&gt;
  &lt;p&gt;There are many annotations available for the open feign client library, but only two are widely used, and they are as follows:&lt;/p&gt; &lt;br/&gt;
  
  &lt;h3&gt;@EnableFeignClients annotation&lt;/h3&gt;
  &lt;p&gt;The &lt;code&gt;@EnableFeignClients&lt;/code&gt; annotation is used at the class level of the main method. The purpose of this annotation is to instruct the spring boot application at the boot level to scan the inferfaces that are declared with the &lt;code&gt;@FeignClient&lt;/code&gt; annotation.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class="java:brush"&gt; @SpringBootApplication
 @EnableFeignClients
 public class OpenFeignClientApplication 
 {
   public static void main(String[] args)
   {
	 SpringApplication.run(OpenFeignClientApplication.class, args);
   }
 }&lt;/code&gt; &lt;/pre&gt;
  
  
  &lt;h3&gt;@FeignClient annotation&lt;/h3&gt; 
  &lt;p&gt;The &lt;code&gt;@FeignClient&lt;/code&gt; annotation is an interface level to declare the Rest API client. There are two main parameters used in this &lt;b&gt;@FeignClient&lt;/b&gt; annotation, and they are as follows: &lt;/p&gt; 
  
  
  &lt;blockquote&gt;
  
    &lt;b&gt;&lt;i&gt;value:&lt;/i&gt;&lt;/b&gt; The name of the service, and if the service registry is enabled in the microservice architecture, then this name will be utilized by the service registry to load balance across all available instances of the service.&lt;br/&gt;
  
     (alert-passed)&lt;/blockquote&gt;
  
    &lt;blockquote&gt;
    &lt;b&gt;&lt;i&gt;url:&lt;/i&gt;&lt;/b&gt; The url parameter expects the URL of the service that you are required to fetch. It should be the base URL only, not an absolute URL, for example &lt;a href = "https://www.learnjavaskills.in/"&gt;https://www.learnjavaskills.in/&lt;/a&gt; &lt;br/&gt;
      (alert-passed)&lt;/blockquote&gt;
  
  &lt;pre&gt;&lt;code class="java"&gt; @FeignClient(value = "student", url="localhost:8080/student/")
 public interface StudentProxy
 {
    
 }&lt;/code&gt;&lt;/pre&gt;
  
&lt;/div&gt;
&lt;br/&gt;

&lt;div&gt;
&lt;h2&gt;How to consume the open Rest API using the open feign client&lt;/h2&gt;
  &lt;hr&gt;
  
&lt;p&gt;Let's consume one of the open APIs using the open feign client library. I've got one service running locally on my machine, and that is called the student service. &lt;/p&gt;
  
&lt;p&gt;The student service exposes one rest API that shares the student's details. Take a look at the following student controller method for more clarity. &lt;/p&gt; &lt;br/&gt; 
  
  &lt;pre&gt;&lt;code class = "java"&gt; @GetMapping(&amp;quot;all-students&amp;quot;)
 public ResponseEntity&amp;lt;List&amp;lt;Student&amp;gt;&amp;gt; getAllStudents()
 {
   List&amp;lt;Student&amp;gt; allStudents = studentService.getAllStudents();
   return ResponseEntity.ok(allStudents);
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;
  
&lt;p&gt;&lt;b&gt;The expected output of the above API is as follows: &lt;/b&gt;&lt;/p&gt; &lt;br/&gt;
  &lt;pre&gt;&lt;code class = "json:brush"&gt; [
  {
    id: 1,
    firstname: &amp;quot;John&amp;quot;,
    lastname: &amp;quot;pear&amp;quot;
  },
  {
    id: 2,
    firstname: &amp;quot;Mayur&amp;quot;,
    lastname: &amp;quot;Rathod&amp;quot;
  },
  {
    id: 3,
    firstname: &amp;quot;Imran&amp;quot;,
    lastname: &amp;quot;Shaikh&amp;quot;
  }
 ] &lt;/code&gt;&lt;/pre&gt;
  
  &lt;br/&gt;
  &lt;p&gt;The full rest API endpoint looks like this: &lt;/p&gt; &lt;br/&gt;
  &lt;blockquote&gt;http://localhost:5000/api/student/all-students&lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt;
  
  
  &lt;h3&gt;Let's configure the above Rest endpoint in our other service where we are expecting to consume this API&lt;/h3&gt; &lt;br/&gt;
  
  &lt;p&gt;&lt;b&gt;Step 1:&lt;/b&gt; Add the base URL of the above student rest API into the &lt;code&gt;application.properties&lt;/code&gt; file like below. The reason for adding this in the properties file is that we will hook up this base url from the application.properties files into the &lt;code&gt;@FeignClient&lt;/code&gt; interface, where we are configuring our proxy to consume the student service. &lt;/p&gt; &lt;br/&gt;
  
  &lt;blockquote&gt;student.base-url = http://localhost:5000/api/student/&lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt; &lt;br/&gt;
  
  &lt;p&gt;&lt;b&gt;Step 2:&lt;/b&gt; Now Create one interface with the &lt;b&gt;@FeignClient&lt;/b&gt; annotation and annotate the main method class with &lt;b&gt;@EnableFeignClients&lt;/b&gt;. So that, Spring Boot looks up the interfaces, which are annotated with the &lt;b&gt;@FeignClient&lt;/b&gt;, to configure the proxy.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; @FeignClient(value = &amp;quot;student&amp;quot;, url=&amp;quot;${student.base-url}&amp;quot;)
 public interface StudentProxy
 {

 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt; 
  
  &lt;p&gt;As you can see, the url parameter of the &lt;b&gt;@FeignClient&lt;/b&gt; is &lt;code&gt;&amp;quot;${student.base-url}&amp;quot;&lt;/code&gt;, It's mean the value of the key, i.e., student.base-url should be fetched from the application.properties file. In this case, the value would be &lt;code&gt;http://localhost:5000/api/student/&lt;/code&gt; which we configured in step 1. &lt;/p&gt;
  
  &lt;br&gt;
  
  &lt;p&gt;&lt;b&gt;Step 3:&lt;/b&gt; Once the above setup is successfully completed, we can look forward to the next step. Let's create an abstract method that will be used to fetch the students details.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java"&gt; @GetMapping(&amp;quot;all-students&amp;quot;)
 public List&amp;lt;Student&amp;gt; getAllStudent(); &lt;/code&gt;&lt;/pre&gt;
  
  &lt;br/&gt;
  &lt;pre&gt;&lt;code class = "java:brush"&gt; public record Student(Long id, String firstname, String lastname)
 {} &lt;/code&gt;&lt;/pre&gt;
 
  &lt;br/&gt; &lt;p&gt;I've use record in this example and If you are using java 8 or 11 then you can also use POJO as well &lt;/p&gt;
  
  &lt;br/&gt;
  
  &lt;p&gt;If you have closely observed that, we declare one abstract method, i.e., &lt;code&gt;getAllStudent()&lt;/code&gt;, with the &lt;u&gt;List &amp;lt;Student&amp;gt;&lt;/u&gt; return type, and then we have annotated this abstract method with the &lt;b&gt;@GetMapping()&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;The intention of this &lt;b&gt;@GetMapping&lt;/b&gt; annotation is that we are instructing the feign client that the HTTP method of the above-mentioned proxy is &lt;code&gt;GET&lt;/code&gt;. So behind the scenes, the feign client will make an API call with the above URL using the HTTP &lt;u&gt;GET&lt;/u&gt; method.&lt;/p&gt; &lt;br/&gt;
 &lt;p&gt;Unlike the HTTP GET method, Feign Client also supports other HTTP methods such as &lt;code&gt;PUT for @PutMapping&lt;/code&gt;, &lt;code&gt;POST for @PostMapping&lt;/code&gt;, and &lt;code&gt;DELETE for @DeleteMapping&lt;/code&gt; annotations, respectively. &lt;p&gt; &lt;br/&gt;
  
  &lt;p&gt;You can also use the &lt;b&gt;@RequestMapping&lt;/b&gt; annotation on the abstract just like we use in the Rest Controller. It works perfectly fine. You can give it a try.&lt;p&gt;
  
  &lt;br/&gt;
  
  &lt;h3&gt; It's time to test feign client API calling&lt;/h3&gt;
    
  &lt;P&gt;Let's create a service class to call the StudentProxy interface the way we usually do.&lt;/P&gt; &lt;br/&gt;
  &lt;pre&gt;&lt;code class="java:brush"&gt; @org.springframework.stereotype.Service
 public class Service
 {
   private final StudentProxy studentProxy;

   @Autowired
   public Service(StudentProxy studentProxy)
   {
     this.studentProxy = studentProxy;
   }

   public List&amp;lt;Student&amp;gt; getStudents()
   {
     return studentProxy.getAllStudent();
   }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;br/&gt;
  &lt;p&gt;Now, we will call the above service method to print the data that we are getting from the Student Service Rest API. I've got to write code in the main method because I don't want to expose any rest API endpoints in that service.&lt;/p&gt;
  
  &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java"&gt; @SpringBootApplication
 @EnableFeignClients
 public class OpenFeignClientApplication
 {
   public static void main(String[] args)
   {
	 ConfigurableApplicationContext configurableApplicationContext = SpringApplication.run(OpenFeignClientApplication.class, args);
	 Service service = (Service) configurableApplicationContext.getBean(&amp;quot;service&amp;quot;);
	 System.out.println(&amp;quot;Fetching all students&amp;quot;);
	 List&amp;lt;Student&amp;gt; allStudent = service.getStudents();
	 allStudent.stream()
	   .forEach(System.out :: println);
   }
 }&lt;/code&gt;&lt;/pre&gt;
 &lt;br/&gt;
  &lt;p&gt;The output of the above code is as follows: &lt;/p&gt; &lt;br/&gt;
    
  &lt;blockquote&gt;Fetching all students &lt;br/&gt;
Student[id=1, firstname=John, lastname=pear] &lt;br/&gt;
Student[id=2, firstname=Mayur, lastname=Rathod] &lt;br/&gt;
Student[id=3, firstname=Imran, lastname=Shaikh]&lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt;
  
&lt;/div&gt;  


&lt;div&gt;
  &lt;h2&gt;ResponseEntity in the feign client interface&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;If you are curious to know, before getting the response from the body, I want to first check the header of the response or the status code of the response.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;The feign client also supports the &lt;code&gt;ResponseEntity&lt;/code&gt; class. With the help of the ResponseEntity class, you can read the &lt;b&gt;header, status, and body of the response&lt;/b&gt;. You just need to replace the return  type with the ResponseEntity class instead of using the body objects, just like below.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; @FeignClient(value = &amp;quot;student&amp;quot;, url=&amp;quot;${student.base-url}&amp;quot;)
 public interface StudentProxy
 {
   @GetMapping(&amp;quot;all-students&amp;quot;)
   ResponseEntity&amp;lt;List&amp;lt;Student&amp;gt;&amp;gt; getAllStudent();
 }&lt;/code&gt;&lt;/pre&gt;
  
  &lt;br/&gt;
  
  &lt;p&gt;Service can be changed as follows:&lt;/p&gt; &lt;br/&gt;
  &lt;pre&gt;&lt;code class = "java:brush"&gt; public List&amp;lt;Student&amp;gt; getStudents()
 {
   ResponseEntity&amp;lt;List&amp;lt;Student&amp;gt;&amp;gt; response = studentProxy.getAllStudent();
   if (response.getStatusCode().value() == 200)
     return response.getBody();
   return Collections.emptyList();
 }&lt;/code&gt;&lt;/pre&gt;
  
&lt;/div&gt;  

&lt;br/&gt;

&lt;div&gt;
  &lt;h2&gt;How to consume a secure Rest API using an open feign client?&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;Till now, we have only seen how to consume the open Rest API. If you are working in an enterprise Java application, then you are most likely consuming the secure API. Let's dig into how we will be able to pass an authorization token in the header of the API request.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Yes, you read correctly. In this section, we will also learn how we are going to pass data in the API request header using the open feign client. However, I'm taking an example of the authorization; you can feel free to send any other request from the header. The process will be exactly the same.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Are you excited to explore how to send authorization tokens? Let's start right below.&lt;/p&gt;
  
  &lt;br/&gt;
  
  &lt;h3&gt;What is the @RequestHeader annotation in the feign client?&lt;/h3&gt;
  &lt;p&gt;The annotation request header means that data should be passed to the request header of the Rest API. As a developer, you may need to send some data in the header of the API request. In such a case, you can utilize the &lt;code&gt;@RequestHeader&lt;/code&gt; annotation. &lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;There are two widely used parameters in the &lt;b&gt;@RequestHeader&lt;/b&gt; annotation, and they are as follows: &lt;/p&gt;
  
    &lt;blockquote&gt;
  &lt;b&gt;&lt;i&gt;value:&lt;/i&gt;&lt;/b&gt; The value defines which header parameter should be aligned. In our case, we are going to send the Basic token under the authorization parameter of the request header for authentication and authorization.
    (alert-passed)&lt;/blockquote&gt;
  
  &lt;blockquote&gt;    
      &lt;b&gt;&lt;i&gt;required:&lt;/i&gt;&lt;/b&gt; The required argument of the @RequestHeader annotation accepts the boolean value. This argument can be utilized to instruct whether the request header parameter is mandatory to consume the API. By default, it's true.
    (alert-passed)&lt;/blockquote&gt;
  
  &lt;h3&gt;Update the code to send the authorization token in the request header&lt;/h3&gt;
  &lt;p&gt;In this example, we are going to use the same student API; I've just enabled the spring security in that service to demonstrate this exercise.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;&lt;b&gt;Step 1:&lt;/b&gt;  Update the student proxy to accept the authorization token in the parameter and annotate it with the @RequestHeader, just like below. &lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; @FeignClient(value = &amp;quot;student&amp;quot;, url=&amp;quot;${student.base-url}&amp;quot;)
 public interface StudentProxy
 {
   @GetMapping(&amp;quot;all-students&amp;quot;)
   ResponseEntity&amp;lt;List&amp;lt;Student&amp;gt;&amp;gt; getAllStudent(@RequestHeader(value = &amp;quot;Authorization&amp;quot;, required = true) String   authorizationToken);
 }&lt;/code&gt; &lt;/pre&gt;
  
  &lt;p&gt;&lt;b&gt;Step 2:&lt;/b&gt; Modify the service layer to generate the Bassic authorization token and pass it to the student proxy just like below.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; public List&amp;lt;Student&amp;gt; getStudents()
 {
   String username = &amp;quot;learnjavaskills.in&amp;quot;;
   String password = &amp;quot;password&amp;quot;;

   String credential = username + &amp;quot;:&amp;quot; + password;
   byte[] encoded = Base64.getEncoder().encode(credential.getBytes());

   String authorizationToken = &amp;quot;Basic &amp;quot; + new String(encoded);

   ResponseEntity&amp;lt;List&amp;lt;Student&amp;gt;&amp;gt; response = studentProxy.getAllStudent(authorizationToken);
   if (response.getStatusCode().value() == 200)
     return response.getBody();
   return Collections.emptyList();
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;
  
  &lt;p&gt;In this section, we have seen how we can send the Basic token, but in most APIs, you may be required to send the Bearer token. In that case, the process is exactly the same: you can use @RequestHeader in the proxy, and you just need to change the mechanism of generating the bearer token.&lt;/p&gt; &lt;br/&gt;
  
&lt;/div&gt; 

&lt;div&gt;
  &lt;h2&gt;Dynamic URL in the open feign client&lt;/h2&gt;
  &lt;hr&gt;
  
  &lt;p&gt;There are some scenarios where you need to consume some of the Rest API by using the dynamic URL. Till now, we have consumed an API with a static URL. Are you excited to learn how to send the URL in the open feign client at runtime? If yes, then let's dive into it.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Before working on the runtime URL, first understand when we may encounter such a requirement. One may say that if the API uses &lt;b&gt;HATEOAS (Hypermedia as the Engine of Application State)&lt;/b&gt; that case we can get several URLs apart from the data in the Rest API response, and we are now bound to execute those links from the HATEOAS response.&lt;p&gt; &lt;br/&gt;
  &lt;p&gt;This is one of my favorite parts of this: connecting the API with the runtime URL. &lt;/p&gt;
  
  &lt;br/&gt;
  
  &lt;h3&gt;How URIs are used in the open feign client&lt;/h3&gt;
  &lt;p&gt;To consume the rest API by sending the runtime url in the open feign client, we just need to accept the URI parameter in the proxy abstract method, just like below: Again, we are using the same student API, but this time we send the URL from the run time.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; @FeignClient(value = &amp;quot;student&amp;quot;, url=&amp;quot;${student.base-url}&amp;quot;)
 public interface StudentProxy
 {
   @GetMapping()
   ResponseEntity&amp;lt;List&amp;lt;Student&amp;gt;&amp;gt; getAllStudent(@RequestHeader(value = &amp;quot;Authorization&amp;quot;, required = true) String authorizationToken,
            URI uri);
 } &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;
  
  &lt;p&gt;If you have closely monitored that, this time we are not appending any static URL under the &lt;code&gt;@GetMapping&lt;/code&gt; annotation, and still open feign clients will be able to consume APIs because of those URI parameters.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Now we need to convert the string url into the URI and pass it to the student proxy abstract method.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; public List&amp;lt;Student&amp;gt; getStudents() throws URISyntaxException
 {
   String username = &amp;quot;learnjavaskills.in&amp;quot;;
   String password = &amp;quot;password&amp;quot;;

   String credential = username + &amp;quot;:&amp;quot; + password;
   byte[] encoded = Base64.getEncoder().encode(credential.getBytes());

   String authorizationToken = &amp;quot;Basic &amp;quot; + new String(encoded);

   String url = &amp;quot;http://localhost:5000/api/student/all-students&amp;quot;;
   URI uri = new URI(url);

   ResponseEntity&amp;lt;List&amp;lt;Student&amp;gt;&amp;gt; response = studentProxy.getAllStudent(authorizationToken, uri);
   if (response.getStatusCode().value() == 200)
     return response.getBody();
   return Collections.emptyList();
 } &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;
  
&lt;/div&gt;  

&lt;div&gt;
  &lt;h2&gt;How to post some data using the open feign client&lt;/h2&gt;
  &lt;hr&gt;
  
  
  &lt;p&gt;Just like earlier I said we can use all the HTTp methods in the open feign client, it's time to understand if we want to send data to the API and how we will be able to achieve this in the open feign client. Let's take a look below.&lt;/p&gt; &lt;br/&gt;
  
  &lt;p&gt;Create an abstract method in the feign client interface and annotate that method with &lt;code&gt;@PostMapping&lt;/code&gt; this time, and add parameters to send the data in the request body of the API. Here we are sending the Student object to add students.&lt;/p&gt; &lt;br/&gt;
  
  &lt;pre&gt;&lt;code class = "java:brush"&gt; @FeignClient(value = &amp;quot;student&amp;quot;, url=&amp;quot;${student.base-url}&amp;quot;)
 public interface StudentProxy
 {
   @PostMapping(&amp;quot;add-student&amp;quot;)
   ResponseEntity&amp;lt;Long&amp;gt; addStudent(Student student);
 } &lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;  &lt;br/&gt;

&lt;p&gt;Your service class may look like the one below to pass the student object.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java:brush"&gt; public Long addStudent()
 {
   ResponseEntity&amp;lt;Long&amp;gt; response = studentProxy.addStudent(new Student(&amp;quot;Jack&amp;quot;, &amp;quot;abram&amp;quot;));
   if (response.getStatusCode().value() == 200)
     return response.getBody();
   return 0L;
 } &lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

&lt;p&gt;Just like this, you can also leverage the &lt;code&gt;@RequestParam&lt;/code&gt; and the &lt;code&gt;@PathVaraible&lt;/code&gt;. If you want me to explain how to use these two annotations in the open feign client, then you can comment in this post, and I'll be happy to add to this.&lt;/p&gt; &lt;br/&gt;
&lt;div&gt;
  
 &lt;div&gt;
   &lt;h2&gt;Logging in to an open feign client request and response&lt;/h2&gt;
   &lt;hr&gt;
   
   &lt;p&gt;Debugging is a crucial part of development. It helps us monitor the request flow of the API and find out the exact root cause of the issue. You can also dubug your API request in the open feign client. &lt;/p&gt; 
   &lt;br/&gt;
   
   &lt;h3&gt;Enabling logging from the application.properties file&lt;/h3&gt;
   
   &lt;p&gt;Let's understand what an open-feign client offers us to debug our API request. First, we must enable debug mode in the application. properties file, following is the syntax&lt;/p&gt; &lt;br/&gt;
   
   &lt;blockquote&gt;logging.level.&amp;lt;project-package&amp;gt; = DEBUG&lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt;
   
   &lt;blockquote&gt;logging.level.in.learnjavaskills.openfeignclient = DEBUG&lt;strike&gt;(code-box)&lt;/strike&gt;&lt;/blockquote&gt;
   
   
   &lt;br/&gt;
   
   &lt;h3&gt;Configure the level of the log&lt;/h3&gt;
   
   &lt;p&gt;Once we have successfully enabled logging, we need to configure the level of the log by creating a bean, just like below.&lt;/p&gt; &lt;br/&gt;
   
   &lt;pre&gt;&lt;code class = "java:brush"&gt; package in.learnjavaskills.openfeignclient;

 import feign.Logger;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;

 @Configuration
 public class OpenFeignClientConfig
 {
   @Bean
   public Logger.Level feignLoggerLevel()
   {
     return Logger.Level.FULL;
   }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

   &lt;p&gt;There are four levels of log in the open feign client log configuration. In the above example, we have enabled FULL log. Let's dive into the deepest level of the log.&lt;/p&gt; &lt;br/&gt;
   
   
     &lt;p&gt;&lt;code&gt;NONE:&lt;/code&gt; This level of log is enabled by default. As the name indicates, none means no log will be printed on the console.&lt;/p&gt; &lt;br/&gt;
   
     &lt;p&gt;&lt;code&gt;BASIC:&lt;/code&gt;  If you want to print only the basic log in the console, such as the request url, response status, and HTTP method used in the API, or you want to monitor the execution time, then the BASIC logging level is best for your case.&lt;/p&gt; &lt;br/&gt;
   
     &lt;p&gt;&lt;code&gt;HEADERS:&lt;/code&gt; The HEADER level will enable the basic level and the request and response API header details to be printed in the console. This can be a good option to enable in production, but if you are happy with the basic details, then I highly encourage you to opt for the BASIC level only.&lt;/p&gt; &lt;br/&gt;
   
     &lt;p&gt;&lt;code&gt;FULL:&lt;/code&gt; The final level is FULL, It will print all the request and response flows of the API. This level is best if you are in the development phase.&lt;/p&gt;  &lt;br/&gt;
     
     
     &lt;p&gt;Let's see the console how logs are populated&lt;/p&gt; &lt;br/&gt;
     
     &lt;pre&gt;&lt;code class = "propeties:brush"&gt; Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         :  [StudentProxy#addStudent] ---&amp;gt; POST http://localhost:5001/api/student/add-student HTTP/1.1
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] Content-Length: 46
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] Content-Type: application/json
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] 
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] {&amp;quot;id&amp;quot;:0,&amp;quot;firstname&amp;quot;:&amp;quot;Jack&amp;quot;,&amp;quot;lastname&amp;quot;:&amp;quot;abram&amp;quot;}
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] ---&amp;gt; END HTTP (46-byte body)
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] &amp;lt;--- HTTP/1.1 200 (25ms)
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] connection: keep-alive
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] content-type: application/json
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] keep-alive: timeout=60
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] transfer-encoding: chunked
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] 
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] 10
 Time stamp with date DEBUG 12116 --- [           main] i.l.openfeignclient.StudentProxy         : [StudentProxy#addStudent] &amp;lt;--- END HTTP (2-byte body) &lt;/code&gt; &lt;/pre&gt;
  &lt;br/&gt;
  
  &lt;/div&gt;
  
  
 &lt;div&gt;
   &lt;h2&gt;Conclusion&lt;/h2&gt;
   &lt;hr&gt;
   &lt;p&gt;In this tutorial, we have seen how to use the open feign client to consume the Rest API, and we have also learned how to enable the log level in the feign client to debug or monitor API requests and the response.&lt;/p&gt; &lt;br/&gt;
   
   &lt;p&gt;We have discussed in detail all the annotations that we can use in the opein feign client. I'll strongly suggest you do a hand on it to understand each and every topic in this article in detail. &lt;/p&gt; &lt;br/&gt;
   
   &lt;p&gt;Feel free to comment on this article about your thoughts or opinions; I'll be happy to address that.&lt;/p&gt; &lt;br/&gt;
   
   &lt;p&gt;Keep learning and keep growing.&lt;/p&gt;
  &lt;/div&gt;  </content><link href="https://www.learnjavaskills.in/feeds/3512974457851572748/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/08/open-feign-client.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/3512974457851572748" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/3512974457851572748" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/08/open-feign-client.html" rel="alternate" title="Open Feign Client | How to Consume Rest API in Spring Cloud or Spring Boot | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidFHI02qdDwj3srTpCrn2GgsDxzKUnUGakRsQzlAKYh-rpa7_0SkNShRtWoEcVETqn5bEp9KyKNXdGZtM5BKlYOFk_SeGwzFp-ySsajDYZzQ0UWvL8eO5n0-VD7UO7ZNluZYh7l4FlBHSQ0mEd1airNsynQ5WqBmGCzRYVgeUjWVPOq-9GSRkLsp6HeXO-/s72-c/open%20feign%20client%20final%20thumbnail.png" width="72"/><thr:total>0</thr:total><georss:featurename>United States</georss:featurename><georss:point>37.09024 -95.712891</georss:point><georss:box>8.780006163821156 -130.869141 65.400473836178847 -60.556641</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-1162724939659496204</id><published>2024-03-03T15:12:00.001+05:30</published><updated>2024-03-03T15:12:50.625+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="Spring Data JPA"/><title type="text">Spring Data JPA Composite Primary Key | Learn Java Skills</title><content type="html">&lt;p&gt;In the enterprise database architecture, it's most common to use the &lt;b&gt;composite primary key&lt;/b&gt;. Spring Data JPA offers us two ways to map the composite primary key in the entity.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;In this article, you will learn how to map the composite primary key in Spring Data JPA using the &lt;code&gt;@IdClass&lt;/code&gt; and &lt;code&gt;@EmbeddedId&lt;/code&gt; annotations, as well as the &lt;code&gt;@Embeddable&lt;/code&gt; annotation.&lt;/p&gt; &lt;br/&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYJdBd4mJAdPfrRE4Hhw5Lgl2rbup2SPWuz77aqRPnIbTJYngr7qZL4pvEaCOu1Oi4VUpr6IhMqQvXgEslhfvBYMNtEKRmse83EUZsPo5hgayIPwvSUYnLL5kaDBUrd-g3HvxGuu9VMbe5GIsA1S0-ad2sNRwS7CP8w_zlbuGDF3mLKZOZZCHoP5BzyNdT/s1600/Spring%20Data%20JPA%20Composite%20Primary%20Key%20Thumbnail%20logo.png" style="display: block; padding: 1em 0; text-align: center; "&gt;&lt;img alt="Spring Data JPA Composite Primary Key Thumbnail Image" border="0" data-original-height="720" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYJdBd4mJAdPfrRE4Hhw5Lgl2rbup2SPWuz77aqRPnIbTJYngr7qZL4pvEaCOu1Oi4VUpr6IhMqQvXgEslhfvBYMNtEKRmse83EUZsPo5hgayIPwvSUYnLL5kaDBUrd-g3HvxGuu9VMbe5GIsA1S0-ad2sNRwS7CP8w_zlbuGDF3mLKZOZZCHoP5BzyNdT/s1600/Spring%20Data%20JPA%20Composite%20Primary%20Key%20Thumbnail%20logo.png"/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;strike&gt;toc&lt;/strike&gt;
&lt;br/&gt;

&lt;h2&gt;What is a composite primary key?&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Before we get into the composite primary key, let's first define the primary key.&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;In SQL, &lt;b&gt;a primary key is a constraint that is unique and not null across table rows&lt;/b&gt;.
&lt;/p&gt;&lt;br/&gt;

&lt;p&gt;Similarly, the composite key is a primary key, but the distinction between the two is that the composite key is the combination of more than one primary key in SQL to identify the unique row in the table.&lt;/p&gt;&lt;br/&gt;

&lt;h2&gt;Overview of Books Table&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Before we go into the design of the composite key, let's first go over the table structure of the books.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;In order to demonstrate this lecture, I've created a &lt;code&gt;books&lt;/code&gt; table with &lt;b&gt;two primary keys, namely &lt;u&gt;book_id&lt;/u&gt; and &lt;u&gt;title&lt;/u&gt;, also known as the composite key in a table&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;I have extra fields in addition to the composite key. You may construct the table on your local system by running the SQL script below, or you can use your existing table if you have one.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "sql"&gt; create database composite_key_tutorial;

 use composite_key_tutorial;

 create table books(
    book_id BIGINT AUTO_INCREMENT,
    title VARCHAR(50),
    book_description VARCHAR(255),
    price DOUBLE,
    unit_sold BIGINT default 0,
    available_quantity BIGINT default 0, 
    PRIMARY KEY(book_id, title)
 );&lt;/code&gt;&lt;/pre&gt;

&lt;br/&gt;


&lt;h2&gt;Composite Key using @IdClass Annotation&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;Let's first use the &lt;b&gt;@IdClass&lt;/b&gt; annotation to begin mapping the composite key in the sprind data JPA.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;The &lt;code&gt;jakarta.persistence&lt;/code&gt; package contains the &lt;code&gt;@IdClass&lt;/code&gt; annotation. The @IdClass annotation defines a composite primary key class that is assigned to numerous entity fields or attributes.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;Composite Primary Key Class&lt;/h3&gt;

&lt;p&gt;If we use the &lt;b&gt;@IdClass&lt;/b&gt; annotation in the Spring Data JPA to map the composite key, we must build one POJO for the primary key fields.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;I'm going to create a &lt;code&gt;BooksId&lt;/code&gt; class for this lecture. Remember that the books table has two primary keys: &lt;code&gt;book_id&lt;/code&gt; and &lt;code&gt;title&lt;/code&gt;. In this BooksId class, we will include both of these primary key fields.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.compositekeytutorial.entity;

 import java.io.Serializable;
 import java.util.Objects;

 public class BooksId implements Serializable
 {
    private Long bookId;
    private String title;

    public BooksId()
    {
    }

    public BooksId(Long bookId, String title)
    {
        this.bookId = bookId;
        this.title = title;
    }

    @Override
    public boolean equals(Object o)
    {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        BooksId booksId = (BooksId) o;
        return Objects.equals(bookId, booksId.bookId) &amp;amp;&amp;amp; Objects.equals(title, booksId.title);
    }

    @Override
    public int hashCode()
    {
        return Objects.hash(bookId, title);
    }
 }&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;The composite primary key class must implement the &lt;code&gt;Serializable&lt;/code&gt; interface, have no and all-argument constructors, and define the &lt;code&gt;equal&lt;/code&gt; and &lt;code&gt;hashcode&lt;/code&gt; methods.(alert-passed)&lt;/blockquote&gt;


&lt;h3&gt;Books Enity Class&lt;/h3&gt;

&lt;p&gt;After successfully creating the composite primary key class, ensure that you declare this ID class in your entity class using the &lt;b&gt;@IdClass&lt;/b&gt; annotation, as shown below.&lt;/p&gt; &lt;br/&gt;


&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.compositekeytutorial.entity;

 import jakarta.persistence.Entity;
 import jakarta.persistence.Id;
 import jakarta.persistence.IdClass;
 import jakarta.persistence.Table;

 import java.math.BigDecimal;
 import java.util.Objects;

 @Entity
 @Table(name = &amp;quot;books&amp;quot;)
 @IdClass(BooksId.class)
 public class BooksEntity
 {
    @Id
    private Long bookId;

    @Id
    private String title;

    private String bookDescription;

    private BigDecimal price;

    private Long unitSold;

    private Long availableQuantity;

    // getter, setter, toString, hashcode, equal
 }&lt;/code&gt; &lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;That's all there is to it for mapping the composite primary key in Spring Data JPA using the @IdClass annotation.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;Books Repository Interface&lt;/h3&gt;

&lt;p&gt;I've also made a repository to test the mapping, which is seen below. I'll run some database transactions to double-check the mapping.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.compositekeytutorial.repository;

 import in.learnjavaskills.compositekeytutorial.entity.BooksEntity;
 import in.learnjavaskills.compositekeytutorial.entity.BooksId;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.stereotype.Repository;

 @Repository
 public interface BooksRepository extends JpaRepository&amp;lt;BooksEntity, BooksId&amp;gt;
 {

 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;p&gt;As seen in the above code, the JpaRepository interface must define generic, i.e., entity, and primary key data type.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;Typically, we declare the primary key's data type. What if we use the composite primary key? In this case, we may utilize the BooksId composite key class that we generated before.&lt;/p&gt; &lt;br/&gt;

&lt;h3&gt;It's time to put the code to the test.&lt;/h3&gt;

&lt;p&gt;I'll use the &lt;a href="https://www.learnjavaskills.in/search/label/JUnit%205"&gt;JUnit&lt;/a&gt; and &lt;a href="https://www.learnjavaskills.in/search/label/Mockito"&gt;Mockito&lt;/a&gt; libraries to &lt;a href="https://www.learnjavaskills.in/search/label/Unit%20Testing"&gt;unit test&lt;/a&gt; the code. In the following test, I attempted to get all of the data from the database and insert some books into the table to confirm that the configuration was functioning properly.&lt;/p&gt; &lt;br/&gt;


&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.compositekeytutorial.repository;

 import in.learnjavaskills.compositekeytutorial.entity.BooksEntity;
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
 import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;

 import java.math.BigDecimal;
 import java.util.List;

 @DataJpaTest
 @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
 class BooksRepositoryTest
 {
    @Autowired
    private BooksRepository booksRepository;

    @Test
    void testFindAll()
    {
        List&amp;lt;BooksEntity&amp;gt; booksRepositoryAll = booksRepository.findAll();
        Assertions.assertThat(booksRepositoryAll).isNotNull()
                .isNotEmpty();
    }

    @Test
    void saveBook()
    {
        BooksEntity booksEntity = new BooksEntity(); 
        booksEntity.setBookId(4L);
        booksEntity.setTitle(&amp;quot;Clean Code&amp;quot;);
        booksEntity.setBookDescription(&amp;quot;Best book to learn writing clean code&amp;quot;);
        booksEntity.setPrice(BigDecimal.TEN);
        booksEntity.setUnitSold(0L);
        booksEntity.setAvailableQuantity(100L);

        BooksEntity save = booksRepository.save(booksEntity);
        Assertions.assertThat(save).isNotNull();
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;Composite Key using @EmbeddedId and @Embeddable Annotation&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;It's time to learn about the second approach for mapping the composite primary key in Spring Data JPA, which involves using the &lt;code&gt;@Embeddable&lt;/code&gt; and the &lt;code&gt;@EmbeddedId&lt;/code&gt; annoations.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;This approach is commonly used in corporate applications. To simplify things, I'm going to utilize the same books table from the previous example to demonstrate this approach.&lt;/p&gt; &lt;br/&gt;

&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;@Embeddable&lt;/th&gt;
    &lt;th&gt;@EmbeddedId&lt;/th&gt;
   &lt;/tr&gt; 
  
  &lt;tr&gt;
    &lt;td&gt;The &lt;code&gt;@Embeddable&lt;/code&gt; annotation denotes a class whose instances are kept as an inherent element of an owner entity and share its identity. Each of the embedded object's permanent characteristics or fields is mapped to the entity's database table.&lt;/td&gt;
    &lt;td&gt;&lt;code&gt;@EmbeddedId&lt;/code&gt; is a unique identifier. To describe a composite primary key that is an embeddable class, this term is used to a persistent field or attribute of an entity class or mapped superclass. When the EmbeddedId annotation is used, there must be only one EmbeddedId annotation and no Id annotation&lt;/td&gt;
  &lt;/tr&gt; 
  
   &lt;tr&gt;
    &lt;td colspan="2"&gt;The &lt;code&gt;jakarta.persistence&lt;/code&gt; package has both &lt;b&gt;@EmbeddedId&lt;/b&gt; and &lt;b&gt;@Embeddable&lt;/b&gt;.&lt;/td&gt;
  &lt;/tr&gt; 
  
&lt;/table&gt;  
&lt;br/&gt;

&lt;h3&gt;Composite Primary Key Class with @Embeddable annotation&lt;/h3&gt;

&lt;p&gt;To include into the entity class, let's construct an Embeddable composite primary key class. Add each of the table's primary keys to this class.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.compositekeytutorial.entity;

 import jakarta.persistence.Embeddable;

 import java.io.Serializable;
 import java.util.Objects;

 @Embeddable
 public class BooksId implements Serializable
 {
    private Long bookId;
    private String title;

    public BooksId()
    {
    }

    public BooksId(Long bookId, String title)
    {
        this.bookId = bookId;
        this.title = title;
    }

    @Override
    public boolean equals(Object o)
    {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        BooksId booksId = (BooksId) o;
        return Objects.equals(bookId, booksId.bookId) &amp;amp;&amp;amp; Objects.equals(title, booksId.title);
    }

    @Override
    public int hashCode()
    {
        return Objects.hash(bookId, title);
    }

    @Override
    public String toString()
    {
        return &amp;quot;BooksId{&amp;quot; + &amp;quot;bookId=&amp;quot; + bookId + &amp;quot;, title=&amp;#39;&amp;quot; + title + &amp;#39;\&amp;#39;&amp;#39; + &amp;#39;}&amp;#39;;
    }
 }&lt;/code&gt;&lt;/pre&gt; 

&lt;blockquote&gt;In addition to implementing the &lt;code&gt;Serializable&lt;/code&gt; Interface and defining the &lt;code&gt;equal&lt;/code&gt; and &lt;code&gt;hashcode&lt;/code&gt; methods, the Composite primary key class needs to be annotated with the &lt;b&gt;@Embeddable&lt;/b&gt; annotations.(alert-passed)&lt;/blockquote&gt; &lt;br/&gt;

&lt;h3&gt;Books Enity Class with @EmbeddedId annotation&lt;/h3&gt;
&lt;p&gt;To map it, embed the composite primary key class into the entity class as shown below.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.compositekeytutorial.entity;

 import jakarta.persistence.*;

 import java.math.BigDecimal;
 import java.util.Objects;

 @Entity
 @Table(name = &amp;quot;books&amp;quot;)
 public class BooksEntity
 {
    @EmbeddedId
    private BooksId bookId;

    private String bookDescription;

    private BigDecimal price;

    private Long unitSold;

    private Long availableQuantity;
    
    // getter, setter, hashcode, equal method
 } &lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h3&gt;It's time to put the code to the test.&lt;/h3&gt;

&lt;p&gt;Because the BooksRepository interface remains unchanged, I have not included it in the following manner to reduce repetition. Let's run the code through unit testing to see whether the setup works as expected.&lt;/p&gt; &lt;br/&gt;

&lt;pre&gt;&lt;code class = "java"&gt; package in.learnjavaskills.compositekeytutorial.repository;

 import in.learnjavaskills.compositekeytutorial.entity.BooksEntity;
 import in.learnjavaskills.compositekeytutorial.entity.BooksId;
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
 import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;

 import java.math.BigDecimal;
 import java.util.List;

 @DataJpaTest
 @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
 class BooksRepositoryTest
 {
    @Autowired
    private BooksRepository booksRepository;

    @Test
    void testFindAll()
    {
        List&amp;lt;BooksEntity&amp;gt; booksRepositoryAll = booksRepository.findAll();
        Assertions.assertThat(booksRepositoryAll).isNotNull()
                .isNotEmpty();

        booksRepositoryAll.forEach(System.out :: println);
    }

    @Test
    void saveBook()
    {
        BooksEntity booksEntity = new BooksEntity();
        BooksId booksId = new BooksId(4L, &amp;quot;Clean Code&amp;quot;);

        booksEntity.setBookId(booksId);
        booksEntity.setBookDescription(&amp;quot;Best book to learn writing clean code&amp;quot;);
        booksEntity.setPrice(BigDecimal.TEN);
        booksEntity.setUnitSold(0L);
        booksEntity.setAvailableQuantity(100L);

        BooksEntity save = booksRepository.save(booksEntity);
        Assertions.assertThat(save).isNotNull();
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br/&gt;

&lt;h2&gt;The distinctions between @IdClass and @EmbeddedId&lt;/h2&gt;
&lt;hr&gt;

&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;&lt;/th&gt;
    &lt;th&gt;@IdClass&lt;/th&gt;
    &lt;th&gt;@EmbeddedId&lt;/th&gt;
  &lt;tr&gt;
    
  &lt;tr&gt;
    &lt;td&gt;&lt;b&gt;Primary Key Redundancy&lt;/b&gt;&lt;/td&gt;
    &lt;td&gt;The primary key must be specified twice in the &lt;code&gt;@IdClass&lt;/code&gt;, once in the composite primary key class and once in the enity class.&lt;/td&gt;
    &lt;td&gt;The &lt;code&gt;@EmbeddedId&lt;/code&gt; annotation is more robust than the &lt;b&gt;@IdClass&lt;/b&gt; annotation since it allows us to bundle the composite primary key in one class, giving you a clear representation of the composite key fields because they are all aggregated in one single class that is only available through the enity class.&lt;/td&gt;
  &lt;tr&gt;
    
  &lt;tr&gt;
    &lt;td&gt;&lt;b&gt;Custom JPQL Query&lt;/b&gt;&lt;/td&gt;
    &lt;td&gt;It is simple to create a custom JPQL query for the primary key. &lt;pre&gt;&lt;code class = "sql"&gt;SELECT b.bookId, b.title FROM Books b; &lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
    &lt;td&gt;If you want to query the composite key, you may need to create a JPQL query like this. &lt;pre&gt;&lt;code class = "sql"&gt;SELECT b.booksId.bookId, b.booksId.title FROM Books b;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;tr&gt;
     
&lt;/table&gt;  &lt;br/&gt;

&lt;h2&gt;Conclussion&lt;/h2&gt;
&lt;hr&gt;

&lt;p&gt;We covered how to map the composite primary key in Spring Data JPA in this lecture. We study the two approaches for mapping the composite key in Spring Data JPA: &lt;b&gt;@IdClass&lt;/b&gt; and &lt;b&gt;@EmbeddedId&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;If you don't mind putting more text on the custom JPQL query, don't want the redundancy of defining an ID twice, and want to bundle a composite key in one class, use &lt;b&gt;@EmbeddedId&lt;/b&gt;.&lt;/p&gt; &lt;br/&gt;

&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;






</content><link href="https://www.learnjavaskills.in/feeds/1162724939659496204/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/11/spring-data-jpa-composite-primary-key.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/1162724939659496204" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/1162724939659496204" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/11/spring-data-jpa-composite-primary-key.html" rel="alternate" title="Spring Data JPA Composite Primary Key | Learn Java Skills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYJdBd4mJAdPfrRE4Hhw5Lgl2rbup2SPWuz77aqRPnIbTJYngr7qZL4pvEaCOu1Oi4VUpr6IhMqQvXgEslhfvBYMNtEKRmse83EUZsPo5hgayIPwvSUYnLL5kaDBUrd-g3HvxGuu9VMbe5GIsA1S0-ad2sNRwS7CP8w_zlbuGDF3mLKZOZZCHoP5BzyNdT/s72-c/Spring%20Data%20JPA%20Composite%20Primary%20Key%20Thumbnail%20logo.png" width="72"/><thr:total>0</thr:total><georss:featurename>India</georss:featurename><georss:point>20.593684 78.96288</georss:point><georss:box>-7.7165498361788458 43.80663 48.903917836178849 114.11913</georss:box></entry><entry><id>tag:blogger.com,1999:blog-6877522804921028548.post-8155081541525664608</id><published>2024-03-03T15:12:00.000+05:30</published><updated>2024-03-03T15:12:35.115+05:30</updated><category scheme="http://www.blogger.com/atom/ns#" term="Spring Cloud"/><title type="text">Spring Cloud Stream and Kafka Streams: The Perfect Duo for Building Event-Driven Architectures | LearnJavaSkills</title><content type="html">&lt;p&gt;Event-Driven Architecture is a software design pattern or model to build an application. The even-driven systems are designed to capture and process the event between the decouple services.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;In an even-driven architecture, two systems can communicate with each other asynchronously.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;The source code is available on &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-stream-kafka-stream" rel="nofollow" target="_blank"&gt;(getButton) #text=(GitHub) #icon=(download) #color=(#000000)&lt;/a&gt;&lt;/p&gt; &lt;br /&gt;

&lt;strike&gt;toc&lt;/strike&gt;
&lt;br/&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXDxJZ1TgawdEr8lJzNYtSCXLRXbeiDuaaeUuLneevh8Azxkr9wPqzUjrmyA9DwnY3HXZynBU2OTwwOwj4Gc2qZTZdLANhWuzUved0jHstY0x7eul0s_UAV3Vd28Eec8AYYjxN2RgLzFHtz9aLs4ydK81lByxwL4rs04XUMbPDckWlpdBnPl77C8uCb1Tw/s1600/thumbnail-image.png" style="clear: right; display: block; float: right; padding: 1em 0px; text-align: center;"&gt;&lt;img alt="Spring Cloud Stream and Kafka Streams: The Perfect Duo for Building Event-Driven Architectures thumbnail image" border="0" data-original-height="1080" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXDxJZ1TgawdEr8lJzNYtSCXLRXbeiDuaaeUuLneevh8Azxkr9wPqzUjrmyA9DwnY3HXZynBU2OTwwOwj4Gc2qZTZdLANhWuzUved0jHstY0x7eul0s_UAV3Vd28Eec8AYYjxN2RgLzFHtz9aLs4ydK81lByxwL4rs04XUMbPDckWlpdBnPl77C8uCb1Tw/s1600/thumbnail-image.png" /&gt;&lt;/a&gt;&lt;/div&gt; &lt;br /&gt;

&lt;h2&gt;What is Spring Cloud Stream?&lt;/h2&gt;
&lt;hr /&gt;

&lt;p&gt;The Spring Cloud Stream is a framework that comes under the umbrella of the Spring Cloud. The Spring Cloud stream offers us the opportunity to build an event-driven microservice architecture.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;The framework offers a versatile programming architecture with support for persistent pub/sub semantics, consumer groups, and stateful partitions, all of which are built on well-known and established Spring idioms and best practices.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;Spring Cloud Stream has a Binder abstraction that may be used to connect to physical destinations at external middleware.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;Spring Cloud Stream supports a number of binder implementations, including but not limited to &lt;code&gt;RabbitMQ&lt;/code&gt;, &lt;code&gt;Apache Kafka&lt;/code&gt;, and &lt;code&gt;Amazon Kinesis&lt;/code&gt;. In this lecture, we will use the &lt;code&gt;Kafka stream&lt;/code&gt;.&lt;/p&gt; &lt;br /&gt;

&lt;h2&gt;What is Apche Kafka?&lt;/h2&gt;
&lt;hr /&gt;

&lt;p&gt;Apache Kafka is a distributed event streaming platform that is open source and used by hundreds of businesses for high-performance data pipelines, streaming analytics, data integration, and mission-critical applications.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;It is a publish-subscribe messaging system that functions as an interface for two parties: the sender and the recipient. More information on kafka may be found &lt;a href="https://www.fintechverse.in/2023/10/apache-kafka-real-time-data-streaming.html" target="_blank"&gt;getButton) #text=(Apache Kafka: The Secret Sauce to Real-Time Data Streaming) #icon=(link) #color=(#2339bd)&lt;/a&gt;&lt;/p&gt; &lt;br /&gt;


&lt;h2&gt;Overview of the Spring Cloud Stream and Kafka Stream projects&lt;/h2&gt;
&lt;hr /&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLpBxAz3UtMFEguyhx0UUKsxhXsAnXr4mDneVFRf-7s9fZNx0rrd7y6quLity5mJTsoOFPFwRfqmAgarD4FBc4mdimFyS1MEyADfPdBA_T194x42bKWTA0CtijnZs9FKFvtcCSUmA4AH8ALhKF1J_V96a6ruGhTv89VTyKlK5YaXa05xHld___o9ehxsVZ/s1600/Spring-cloud-stream-kafka-stream-project-archetecture.png" style="display: block; padding: 1em 0px; text-align: center;"&gt;&lt;img alt="Spring Cloud Stream and Kafka Stream projects Architectures" border="0" data-original-height="720" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLpBxAz3UtMFEguyhx0UUKsxhXsAnXr4mDneVFRf-7s9fZNx0rrd7y6quLity5mJTsoOFPFwRfqmAgarD4FBc4mdimFyS1MEyADfPdBA_T194x42bKWTA0CtijnZs9FKFvtcCSUmA4AH8ALhKF1J_V96a6ruGhTv89VTyKlK5YaXa05xHld___o9ehxsVZ/s1600/Spring-cloud-stream-kafka-stream-project-archetecture.png" /&gt;&lt;/a&gt;&lt;/div&gt; &lt;br /&gt;


&lt;p&gt;In this lecture, we will build a project named &lt;b&gt;BookMyMovie&lt;/b&gt;. This project will be in charge of booking the movie show, and we will construct this software leveraging the &lt;b&gt;even-driven architecture with the spring cloud stream and kafka stream&lt;/b&gt;.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;To begin, we will construct the Rest API by utilizing the Spring cloud stream and the Kafka stream to receive the payload (a movie ticket book request), which will then send the payload data in JSON format to the Kafka topic, i.e., &lt;code&gt;movie-ticket-request-topic&lt;/code&gt;.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;We will create a stream processing with Kafka stream in order to look for the event in the &lt;code&gt;movie-ticket-request-topic&lt;/code&gt; kafka topic&amp;nbsp;and &lt;b&gt;perform real-time activities&lt;/b&gt; before sending to the &lt;code&gt;movie-ticket-booked-topic&lt;/code&gt; kafka topic.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;After that, we'll look at how to consume messages from the &lt;code&gt;movie-ticket-request-topic&lt;/code&gt; kafka topic.&lt;/p&gt; &lt;br /&gt;

&lt;h2&gt;BookMyMovie Service&lt;/h2&gt;
&lt;hr /&gt;

&lt;p&gt;The application design is as follows: a user sends a request to the backend Rest API, after which the application validates the movie ticket request and transforms the data before sending it back to the Kafk topic i.e., &lt;code&gt;movie-ticket-request-topic&lt;/code&gt;.&lt;/p&gt; &lt;br /&gt;


&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWpAlhOHAZgM1EqWKvYGi_Dzi7voNLWyUxr6-L-rUBkDiEfh3HpaNbHPx3s2D8yr5VxxW5XiBtihjFBSomt2aTJfJulW06mM0LYr0S9plUTxAQXXS-aZ8iHDJaFRu05sl4FktxoFnOI0KGz0hxLGfnYYpPLpcRkCMiZ5a65WtGyfC3TzspcM_lI3QjbX1K/s1600/Expose-rest-api-to-send-message-to-kafka-topic-crop.png" style="display: block; padding: 1em 0px; text-align: center;"&gt;&lt;img alt="BookMyMOvie Service architecture" border="0" data-original-height="338" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWpAlhOHAZgM1EqWKvYGi_Dzi7voNLWyUxr6-L-rUBkDiEfh3HpaNbHPx3s2D8yr5VxxW5XiBtihjFBSomt2aTJfJulW06mM0LYr0S9plUTxAQXXS-aZ8iHDJaFRu05sl4FktxoFnOI0KGz0hxLGfnYYpPLpcRkCMiZ5a65WtGyfC3TzspcM_lI3QjbX1K/s1600/Expose-rest-api-to-send-message-to-kafka-topic-crop.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;h3&gt;Dependencies&lt;/h3&gt;
  
  &lt;p&gt;In your project, include the following dependencies: The build.gradle file is shown below.&lt;/p&gt; &lt;br /&gt;
  
  &lt;pre&gt;&lt;code class="groovy"&gt; plugins {
	id 'java'
	id 'org.springframework.boot' version '3.1.6'
	id 'io.spring.dependency-management' version '1.1.4'
 }

 group = 'in.learnjavaskills'
 version = '0.0.1-SNAPSHOT'

 java {
	sourceCompatibility = '17'
 }

 repositories {
	mavenCentral()
 }

 ext {
	set('springCloudVersion', "2022.0.4")
 }

 dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.cloud:spring-cloud-stream'
	implementation 'org.springframework.cloud:spring-cloud-stream-binder-kafka'
	implementation 'org.springframework.kafka:spring-kafka'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.cloud:spring-cloud-stream-test-binder'
	testImplementation 'org.springframework.kafka:spring-kafka-test'
 }

 dependencyManagement {
	imports {
		mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
	}
 }

 tasks.named('bootBuildImage') {
	builder = 'paketobuildpacks/builder-jammy-base:latest'
 }

 tasks.named('test') {
	useJUnitPlatform()
 } &lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpZvv46CDF9vbcRoHzKaATNZlHnH0neEypCOzPTmH4aHnF9X65YLbeA9B28pYYKTSNPoGD9dJGLTpMwMEuh8_bntnfLcmo_4GHc7idXzon4zexzIxBSfq3y14vBa3fItFA15oabySLIHNtbyw-h6azFIFn1ksIBHqVaXzquO91hi0CfdBGL1HLdyfY8xaH/s1600/book-my-movie-service-spring-initializr.png" style="display: block; padding: 1em 0px; text-align: center;"&gt;&lt;img alt="book-my-movie-service spring initializer project image" border="0" data-original-height="577" data-original-width="1205" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpZvv46CDF9vbcRoHzKaATNZlHnH0neEypCOzPTmH4aHnF9X65YLbeA9B28pYYKTSNPoGD9dJGLTpMwMEuh8_bntnfLcmo_4GHc7idXzon4zexzIxBSfq3y14vBa3fItFA15oabySLIHNtbyw-h6azFIFn1ksIBHqVaXzquO91hi0CfdBGL1HLdyfY8xaH/s1600/book-my-movie-service-spring-initializr.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;h3&gt;Configuration of the Kafka Binder Properties&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;spring.cloud.stream.kafka.binder.brokers&lt;/code&gt; property is the list of brokers to which the Kafka binder connects.&lt;/p&gt;

&lt;blockquote&gt;Default:&amp;nbsp;&lt;b&gt;localhost&lt;/b&gt;(alert-success)&lt;/blockquote&gt; &lt;br /&gt;

&lt;pre&gt;&lt;code class="properties"&gt; spring.cloud.stream.kafka.binder.brokers = 3.80.128.59:9092&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;

&lt;p&gt;Because I'm hosting my Kafka server on an AWS EC2 instance in a single broker node, I must supply my EC2 instance's public IP address together with the right port, which in my case is &lt;code&gt;3.80.128.59:9092&lt;/code&gt;.&lt;/p&gt; 

&lt;blockquote&gt;As you can see here, I utilized the IP address of the Kafak broker server node, however this is not the best practice. You should always utilize host names rather than IP addresses.(alert-warning)&lt;/blockquote&gt; &lt;br /&gt;

&lt;p&gt;If you are running Kafka on your local system, you do not need to include this setting in your application. Spring cloud stream search kafa broker server is on &lt;code&gt;localhost:9092&lt;/code&gt; by default.&lt;/p&gt; &lt;br /&gt;

&lt;h3&gt;Controller&lt;/h3&gt;

&lt;p&gt;To accept user input, we may offer a single rest endpoint that will receive user input and then transmit the same data to the kafka topic, i.e., &lt;b&gt;movie-ticket-request-topic&lt;/b&gt;.&lt;/p&gt; &lt;br /&gt;

&lt;pre&gt;&lt;code class="java"&gt; package in.learnjavaskills.bookmymovieservice.controller;

 import in.learnjavaskills.bookmymovieservice.dto.MovieTicketBookingRequest;
 import in.learnjavaskills.bookmymovieservice.service.InitiateMovieTicketBookingService;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;

 @RestController
 @RequestMapping("/movies/")
 public class BookMyMovieController
 {
    private final InitiateMovieTicketBookingService initiateMovieTicketBookingService;

    public BookMyMovieController(InitiateMovieTicketBookingService initiateMovieTicketBookingService) {
        this.initiateMovieTicketBookingService = initiateMovieTicketBookingService;
    }

    @PostMapping("book-ticket")
    ResponseEntity&amp;lt;String&amp;gt; bookMovieTicket(@RequestBody MovieTicketBookingRequest movieTicketBookingRequest) {
        return initiateMovieTicketBookingService.publishMovieTicketBookingMessage(movieTicketBookingRequest);
    }
 } &lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;

&lt;p&gt;The &lt;code&gt;MovieTicketBookingRequest.class&lt;/code&gt;, as shown in the &lt;b&gt;book-ticket&lt;/b&gt; API, is used to accept the user's request payload. Let's make the &lt;b&gt;MovieTicketBookingRequest&lt;/b&gt; class quickly.&lt;/p&gt; &lt;br /&gt;

&lt;pre&gt;&lt;code class="java"&gt; package in.learnjavaskills.bookmymovieservice.dto;

 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
 import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;

 import java.time.LocalDateTime;
 import java.util.Objects;

 public class MovieTicketBookingRequest
 {
    private String movieName;
    private byte screenNumber;
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime movieShowTime;
    private String seatNumber;
    private String user;

   // getter, setter, toString, equal and hashcode method's
 }&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;


&lt;h3&gt;InitiateMovieTicketBookingService class&lt;/h3&gt;
&lt;p&gt;It's time to build some business logic in &lt;code&gt;InitiateMovieTicketBookingService.class&lt;/code&gt; and then send a message to the movie-ticket-request-topic&amp;nbsp;Kafka topic.&lt;/p&gt; &lt;br /&gt;


&lt;pre&gt;&lt;code class="java"&gt; package in.learnjavaskills.bookmymovieservice.service;

 import in.learnjavaskills.bookmymovieservice.dto.MovieTicketBookingMessage;
 import in.learnjavaskills.bookmymovieservice.dto.MovieTicketBookingRequest;
 import org.springframework.cloud.stream.function.StreamBridge;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.messaging.Message;
 import org.springframework.messaging.support.MessageBuilder;
 import org.springframework.stereotype.Service;
 import org.springframework.util.MimeTypeUtils;

 import java.util.Objects;

 @Service
 public class InitiateMovieTicketBookingService
 {

    private final StreamBridge streamBridge;

    private final String topicName = "movie-ticket-request-topic";

    public InitiateMovieTicketBookingService(StreamBridge streamBridge) {
        this.streamBridge = streamBridge;
    }

    /**
     * Publishing message to the kafka topic
     * @param movieTicketBookingRequest
     * @return response
     */
    public ResponseEntity&amp;lt;String&amp;gt; publishMovieTicketBookingMessage(MovieTicketBookingRequest movieTicketBookingRequest) {
        if (Objects.isNull(movieTicketBookingRequest))
            return ResponseEntity.badRequest().body("Movie Ticket Booking Request must be non null");

        MovieTicketBookingMessage movieTicketBookingMessage = new MovieTicketBookingMessage(movieTicketBookingRequest);
        Message&amp;lt;MovieTicketBookingMessage&amp;gt; movieTicketBookingMessageMessage = generateMessage(movieTicketBookingMessage);
        boolean isMessageSend = streamBridge.send(topicName, movieTicketBookingMessageMessage, MimeTypeUtils.APPLICATION_JSON);
        if (isMessageSend)
            return ResponseEntity.ok("Movie booking ticket initiated success");
        else return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED)
                .body("Unable to send message to kafka topic");
    }


    /**
     * Generate message to send to the kafka topic
     * @param movieTicketBookingMessage
     * @return Message
     */
    private Message&amp;lt;MovieTicketBookingMessage&amp;gt; generateMessage(MovieTicketBookingMessage movieTicketBookingMessage) {
        if (Objects.isNull(movieTicketBookingMessage))
            return null;

        return MessageBuilder.withPayload(movieTicketBookingMessage)
                .build();
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;

&lt;p&gt;Let's build a &lt;code&gt;MovieTicketBookingMessage&lt;/code&gt; &lt;a href="https://www.learnjavaskills.in/2023/09/what-is-a-record-in-java.html"&gt;record&lt;/a&gt; that is in charge of collecting Kafka message data.&lt;/p&gt; &lt;br /&gt;


&lt;pre&gt;&lt;code class="java"&gt; package in.learnjavaskills.bookmymovieservice.dto;

 import com.fasterxml.jackson.annotation.JsonFormat;

 import java.time.LocalDateTime;

 public record MovieTicketBookingMessage(String movieName, byte screenNumber,
         @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
         LocalDateTime movieShowTime,
         String seatNumber,
         @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
         LocalDateTime messageGeneratedOn,
         String users)
 {
    public MovieTicketBookingMessage(MovieTicketBookingRequest movieTicketBookingRequest) {
        this (movieTicketBookingRequest.getMovieName(),
                movieTicketBookingRequest.getScreenNumber(),
                movieTicketBookingRequest.getMovieShowTime(),
                movieTicketBookingRequest.getSeatNumber(),
                LocalDateTime.now(),
                movieTicketBookingRequest.getUser());
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;

&lt;h3&gt;In the spring cloud stream, how do I send a message to the Kafka topic?&lt;/h3&gt;

&lt;p&gt;To deliver the message into the Kafka topic, the Spring cloud stream provides the &lt;code&gt;StreamBridge&lt;/code&gt; class. The StreamBridge class is part of the &lt;b&gt;org.springframework.cloud.stream.function package&lt;/b&gt;.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;The &lt;u&gt;StreamBridge&lt;/u&gt; class allows users to transfer data to an output binding.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;While the user rarely needs to manually transmit data in a normal &lt;b&gt;spring-cloud-stream application situation&lt;/b&gt;, there are instances when the sources of data are outside of the spring-cloud-stream context, and so we need to bridge such foreign sources with spring-cloud-stream.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;Because our data comes from an API, we must utilize StreamBridge in this scenario.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;We can transmit the message to the Kafka topic using the &lt;code&gt;send&lt;/code&gt; method of the &lt;b&gt;StreamBridge&lt;/b&gt; class. The StreamBridge class contains an extensive number of overloaded send methods. Here in the above-mentioned example, we utilize the following method:.&lt;/p&gt; &lt;br /&gt;

&lt;pre&gt;&lt;code class="java"&gt; public boolean send(String bindingName, Object data, MimeType outputContentType)&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;

&lt;p&gt;The &lt;code&gt;bindingName&lt;/code&gt; is simply the name of the Kafka topic. The &lt;code&gt;data&lt;/code&gt; argument can represent our kafak message, and the &lt;code&gt;MimeType&lt;/code&gt; field can describe what sort of message we are delivering to the kafka topic.&lt;/p&gt; &lt;br /&gt;

&lt;h3&gt;Message interface in the spring cloud stream&lt;/h3&gt;

&lt;p&gt;The Kafa message payload can be wrapped in the &lt;code&gt;Message&lt;/code&gt; interface. The Message interface is found in the &lt;b&gt;package org.springframework.messaging&lt;/b&gt; and is used for &lt;b&gt;representing messages with the header and body&lt;/b&gt;.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;The &lt;code&gt;generateMessage()&lt;/code&gt; method&amp;nbsp;wraps the payload, i.e., &lt;b&gt;MovieTicketBookingMessage&lt;/b&gt;, inside the Message interface.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;If you're wondering how I can send the message to the Kafka topic with the key, that's also feasible using the Message interface since we simply need to include the header for the key to send the message into the Kafka topic with the key.&lt;/p&gt; &lt;br /&gt;

&lt;pre&gt;&lt;code class="java"&gt; MessageBuilder.withPayload(movieTicketBookingMessage)
     .setHeader(KafkaHeaders.KEY, "YOUR_KEY_HERE".getBytes())
     .build();&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;


&lt;h2&gt;Booking Process Service&lt;/h2&gt;
&lt;hr /&gt;

&lt;p&gt;Create a streaming application with Spring Cloud Stream and Kafka Stream.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;The &lt;code&gt;booking-process-service&lt;/code&gt; is a streaming service that reads the Kafka message from the &lt;code&gt;movie-ticket-request-topic&lt;/code&gt; and writes it to the &lt;code&gt;movie-ticked-booked-topic&lt;/code&gt;.
&lt;/p&gt; &lt;br /&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIJx7gzbyqwaBsk-1CKF__2f7H0t9nebin78WQOkdVQDB6iQQFLu0IHqe8k9np4OVxcda_J6FwiyMeoXHnO9ahBxSOTwKPcjlSm422XLGth80ASgzmbDWQ910qGbs3swOsy7cw4NioBOGZL9ddcySBUFG5ah7PNdcaRkGAk_op1cHvlcit73ZQv7cElADP/s1600/kafka-stream-application.png" style="display: block; padding: 1em 0px; text-align: center;"&gt;&lt;img alt="booking-process-service diagram" border="0" data-original-height="720" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIJx7gzbyqwaBsk-1CKF__2f7H0t9nebin78WQOkdVQDB6iQQFLu0IHqe8k9np4OVxcda_J6FwiyMeoXHnO9ahBxSOTwKPcjlSm422XLGth80ASgzmbDWQ910qGbs3swOsy7cw4NioBOGZL9ddcySBUFG5ah7PNdcaRkGAk_op1cHvlcit73ZQv7cElADP/s1600/kafka-stream-application.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;The Kafka Streams binder supports the three primary forms of Kafka Streams: &lt;code&gt;KStream&lt;/code&gt; , &lt;code&gt;KTable&lt;/code&gt; , and &lt;code&gt;GlobalKTable&lt;/code&gt; .&lt;/p&gt; &lt;br /&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0srrmzR-o-P-45RunMBn0WNsOCgPa-cmzgmHUpvKUqLO79KXgiKQ8LTtbW6kQnE1cd-hvwikvukMRfB_iYV8EIz73EQprDKhZzuxfZvvaSMXvNtPbdSJ8NKYmCAqdNudQm5h1wQVNoZuAWIteTE1cDqGLZ0ORU6SNWOS8Cv9h300z_1RAYloBXoleDyE0/s1600/booking-process-service-spring-initializr.png" style="display: block; padding: 1em 0px; text-align: center;"&gt;&lt;img alt="booking-process-service spring initializer project setup" border="0" data-original-height="571" data-original-width="1212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0srrmzR-o-P-45RunMBn0WNsOCgPa-cmzgmHUpvKUqLO79KXgiKQ8LTtbW6kQnE1cd-hvwikvukMRfB_iYV8EIz73EQprDKhZzuxfZvvaSMXvNtPbdSJ8NKYmCAqdNudQm5h1wQVNoZuAWIteTE1cDqGLZ0ORU6SNWOS8Cv9h300z_1RAYloBXoleDyE0/s1600/booking-process-service-spring-initializr.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;h3&gt;Functional Style&lt;/h3&gt;

&lt;p&gt;Beginning with &lt;b&gt;Spring Cloud Stream 3.0.0&lt;/b&gt;, the Kafka Streams binder allows applications to be created and developed utilizing the functional programming style accessible in Java 8.&lt;/p&gt; &lt;br /&gt; 

&lt;p&gt;This means that the applications may be expressed concisely as a lambda expression of the kinds &lt;code&gt;java.util.function.Function&lt;/code&gt; or &lt;code&gt;java.util.function.Consumer&lt;/code&gt; .&lt;/p&gt; &lt;br /&gt;

&lt;h3&gt;Process Movie Ticket Booking Function&lt;/h3&gt;

&lt;p&gt;Let's use the functional interface to develop a function(processMovieTicketBooking) for Kafka streaming. This function is in charge of reading the message from the &lt;b&gt;movie-ticket-request-topic&lt;/b&gt; and writing it back into the &lt;b&gt;movie-ticked-booked-topic&lt;/b&gt;.&lt;/p&gt; &lt;br /&gt;


&lt;pre&gt;&lt;code class="java"&gt; package in.learnjavaskills.bookingprocessservice.function;

 import in.learnjavaskills.bookingprocessservice.dto.MovieTicketBookedSuccessfully;
 import in.learnjavaskills.bookingprocessservice.dto.MovieTicketBookingMessage;
 import org.apache.kafka.streams.KeyValue;
 import org.apache.kafka.streams.kstream.KStream;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;

 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.time.LocalDateTime;
 import java.util.Base64;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.UUID;
 import java.util.function.Function;

 @Configuration
 public class MovieTicketBookingProcess
 {

    @Bean("processMovieTicketBooking")
    public Function&amp;lt;KStream&amp;lt;String, MovieTicketBookingMessage&amp;gt;, KStream&amp;lt;String, MovieTicketBookedSuccessfully&amp;gt;&amp;gt; processMovieTicketBooking() {
        return movieBookingRequestMessageKStream -&amp;gt; movieBookingRequestMessageKStream.map( (messageKey, movieBookingRequestMessage) -&amp;gt; {
            System.out.println("New message arrived with key : " + messageKey + " and values : " + movieBookingRequestMessage.toString());
            Optional&amp;lt;MovieTicketBookedSuccessfully&amp;gt; movieTicketBookedSuccessfully = bookMovieTicket(movieBookingRequestMessage);
            return new KeyValue&amp;lt;String, Optional&amp;lt;MovieTicketBookedSuccessfully&amp;gt;&amp;gt;(messageKey, movieTicketBookedSuccessfully);
        }).filter((messageKey, movieTicketBookedSuccessfullyOptional) -&amp;gt; {
            if (movieTicketBookedSuccessfullyOptional.isPresent()) {
                MovieTicketBookedSuccessfully movieTicketBookedSuccessfully = movieTicketBookedSuccessfullyOptional.get();
                System.out.println("Booking movie ticket for movie id : " + movieTicketBookedSuccessfully.movieId());
                return  true;
            } return false;
        }).map((messageKey, movieTicketBookedSuccessfully) -&amp;gt; new KeyValue&amp;lt;&amp;gt;(messageKey, movieTicketBookedSuccessfully.get()));
    }

    private Optional&amp;lt;MovieTicketBookedSuccessfully&amp;gt; bookMovieTicket(MovieTicketBookingMessage movieTicketBookingMessage) {
        if (Objects.isNull(movieTicketBookingMessage))
            return Optional.empty();

        Optional&amp;lt;String&amp;gt; moviePassCode = generateMoviePassCode(movieTicketBookingMessage);
        if (!moviePassCode.isPresent())
            return Optional.empty();

        MovieTicketBookedSuccessfully movieTicketBookedSuccessfully = new MovieTicketBookedSuccessfully(movieTicketBookingMessage.movieName() + UUID.randomUUID().toString(),
                movieTicketBookingMessage.users(),
                moviePassCode.get(),
                LocalDateTime.now());
        return Optional.of(movieTicketBookedSuccessfully);
    }

    private Optional&amp;lt;String&amp;gt; generateMoviePassCode(MovieTicketBookingMessage movieTicketBookingMessage) {
        if (Objects.isNull(movieTicketBookingMessage))
            return Optional.empty();

        String code = movieTicketBookingMessage.movieName() + " " + movieTicketBookingMessage.users()
                      + " " + movieTicketBookingMessage.seatNumber();

        try  {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
            byte[] digest = messageDigest.digest(code.getBytes(StandardCharsets.UTF_8));
            return Optional.of(Base64.getEncoder().encodeToString(digest));
        }
        catch (NoSuchAlgorithmException e) {
            return Optional.empty();
        }
    }
 }&lt;/code&gt;&lt;/pre&gt; 

&lt;blockquote&gt;For the sake of simplicity, I've omitted the database communication here. You may also utilize the database to validate or store movie tickets details.
(alert-passed)&lt;/blockquote&gt; &lt;br /&gt;

&lt;p&gt;The &lt;code&gt;processMovieTicketBooking&lt;/code&gt; function is binding with the single inbound with the &lt;b&gt;KStream&amp;lt;String, MovieTicketBookingMessage&amp;gt;&lt;/b&gt; and single outbound with the&lt;b&gt;&amp;nbsp;KStream&amp;lt;String, MovieTicketBookedSuccessfully&amp;gt;&lt;/b&gt;.&lt;/p&gt; &lt;br /&gt;

&lt;pre&gt;&lt;code class="java"&gt; package in.learnjavaskills.bookingprocessservice.dto;

 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;

 import java.time.LocalDateTime;

 public record MovieTicketBookingMessage(String movieName, byte screenNumber,
         @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
         @JsonDeserialize(using = LocalDateTimeDeserializer.class)
         LocalDateTime movieShowTime,
         
         String seatNumber,
         
         @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
         @JsonDeserialize(using = LocalDateTimeDeserializer.class)
         LocalDateTime messageGeneratedOn,
         
         String users)
 {} &lt;/code&gt; &lt;/pre&gt; &lt;br /&gt;


&lt;pre&gt;&lt;code class="java"&gt; package in.learnjavaskills.bookingprocessservice.dto;

 import com.fasterxml.jackson.annotation.JsonFormat;

 import java.time.LocalDateTime;

 public record MovieTicketBookedSuccessfully(String movieId,
         String user,
         String moviePassCode,
         
         @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
         LocalDateTime messageGeneratedOn)
 {}&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;

&lt;h3&gt;What exactly is KStream?&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;KStream&amp;lt;K,V&amp;gt;&lt;/code&gt; is an interface in the &lt;b&gt;org.apache.kafka.streams.kstream package&lt;/b&gt;.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;KStream is an abstraction of a record stream of &lt;code&gt;KeyValue&lt;/code&gt; pairs, i.e., each record in the real world is an individual entity or event. For example, if user A&amp;nbsp;purchases two goods, item1 and item2, there may be two records &amp;lt;K:item1&amp;gt; and &amp;lt;K:item2&amp;gt;,&amp;nbsp;in the stream.&lt;/p&gt; &lt;br /&gt;

&lt;h3&gt;What exactly is KeyValue?&lt;/h3&gt;

&lt;p&gt;The class &lt;code&gt;KeyValue&amp;lt;K, V&amp;gt;&lt;/code&gt; is part of the org.apache.kafka.streams package.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;For each Kafka Streams record, a key-value pair is defined. If the record is directly from a Kafka topic, its key/value is the message key/value.&lt;/p&gt; &lt;br /&gt;

&lt;h3&gt;Kafka Broker Configuration in the Booking Process Service&lt;/h3&gt;

&lt;p&gt;First, in the &lt;code&gt;application.properties&lt;/code&gt; file, we must configure our Kafka broker node, and I have named my service &lt;b&gt;booking-process-service-application&lt;/b&gt;.&lt;/p&gt; &lt;br /&gt;

&lt;pre&gt;&lt;code class="properties"&gt; # application name
 spring.application.name = booking-process-service-application

 # broker server node
 spring.cloud.stream.kafka.binder.brokers = 54.146.205.212:9092 &lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;


&lt;p&gt;Then you may give &lt;code&gt;spring.cloud.function.definition=processMovieTicketBooking&lt;/code&gt; definitions. With the binder's functional composition support&lt;/p&gt; &lt;br /&gt;

&lt;pre&gt;&lt;code class="properties"&gt; # kafka binder name - method name of your function
 spring.cloud.function.definition = processMovieTicketBooking &lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;


&lt;p&gt;Enable the kafka consumer group to consume messages in a group. This property allows you to consume the message in the form of a group name; in our example, &lt;b&gt;booking-process-service-application&lt;/b&gt;.&lt;/p&gt; &lt;br /&gt;

&lt;pre&gt;&lt;code class="properties"&gt; # kafka consumer group name
 spring.cloud.stream.bindings.processMovieTicketBooking.group = ${spring.application.name}&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;

&lt;p&gt;The following are the Kafka topic name binder and deserialization configuration properties:.&lt;/p&gt;&lt;br /&gt;

&lt;pre&gt;&lt;code class="properties"&gt; # kafka topic name
 spring.cloud.stream.bindings.processMovieTicketBooking-in-0.destination = movie-ticket-request-topic
 spring.cloud.stream.bindings.processMovieTicketBooking-out-0.destination = movie-ticket-booked-topic

 # deserialization configuration
 spring.cloud.stream.kafka.bindings.processMovieTicketBooking.in-0.consumer.configuration.key.deserializer = org.apache.kafka.common.serialization.StringDeserializer
 spring.cloud.stream.kafka.bindings.processMovieTicketBooking.in-0.consumer.configuration.value.deserializer = org.springframework.kafka.support.serializer.JsonDeserializer

 spring.cloud.stream.kafka.bindings.processMovieTicketBooking.in-0.producer.configuration.key.deserializer = org.apache.kafka.common.serialization.StringDeserializer
 spring.cloud.stream.kafka.bindings.processMovieTicketBooking.in-0.producer.configuration.value.deserializer = org.springframework.kafka.support.serializer.JsonDeserializer&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEy8GFlxDAmKuAtU5xhrmyX9KzsM_SMZHnbNm9C5eZFnok604iIXreQf4qPsj-1-6ScW_AiC87HLxcQh1xBRlowCtxe6X2zN_bBrkpGScnTOc2GgWYIwp7SGM-db-tBirtEYOVGmVAhKkjeMUeIjaL4RqBB6AjZWthCh-Twlnm-afJ5juLdfCMM9XwRIaB/s1600/binder-explanation.png" style="display: block; padding: 1em 0px; text-align: center;"&gt;&lt;img alt="binder-explanation diagram" border="0" data-original-height="720" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEy8GFlxDAmKuAtU5xhrmyX9KzsM_SMZHnbNm9C5eZFnok604iIXreQf4qPsj-1-6ScW_AiC87HLxcQh1xBRlowCtxe6X2zN_bBrkpGScnTOc2GgWYIwp7SGM-db-tBirtEYOVGmVAhKkjeMUeIjaL4RqBB6AjZWthCh-Twlnm-afJ5juLdfCMM9XwRIaB/s1600/binder-explanation.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;h3&gt;Dependencies&lt;/h3&gt;

&lt;pre&gt;&lt;code class="groovy"&gt; dependencies {
	implementation 'org.apache.kafka:kafka-streams'
	implementation 'org.springframework.cloud:spring-cloud-stream'
	implementation 'org.springframework.cloud:spring-cloud-stream-binder-kafka-streams'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.cloud:spring-cloud-stream-test-binder'
	// required this dependencies to deserialize java 8 date/time
	implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.16.0'
 }&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;

 
&lt;h2&gt;Update Booked Status Service&lt;/h2&gt;
&lt;hr /&gt;
 
&lt;p&gt;Finally, using the Spring Cloud Stream and the Kafka Stream, we will develop another service to consume messages from the Kafka topic.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;In this service, we will utilize the Java 8 consumer interface to consume the message from the Kafak topic in a functional approach, similar to the previous example.&lt;/p&gt; &lt;br /&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjnprd-PWDUimVhS4UNC-aNAKEqeR85mH88GXggbdE7WLLKXTKgPgD37i60zYwg_nC6kxQacrMoXzE0mqXo7ljFA4lBKDrjSEPTPzNkngy4CmHk391nK_10sSzvoRRpF3cVoUZBMnAp99AxazELsuhiDEATiKhAr93QAvgdqNrpAb3XGzQysCSRirvYVC9/s1600/Consume-messages-from-topic-crop.png" style="display: block; padding: 1em 0px; text-align: center;"&gt;&lt;img alt="Consuming messages from kafka topic diagram" border="0" data-original-height="543" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjnprd-PWDUimVhS4UNC-aNAKEqeR85mH88GXggbdE7WLLKXTKgPgD37i60zYwg_nC6kxQacrMoXzE0mqXo7ljFA4lBKDrjSEPTPzNkngy4CmHk391nK_10sSzvoRRpF3cVoUZBMnAp99AxazELsuhiDEATiKhAr93QAvgdqNrpAb3XGzQysCSRirvYVC9/s1600/Consume-messages-from-topic-crop.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5BwpTO89nBdleoRYPLVTYkvBi_a1u3dm7czNTy50y0WjQhwvQj3Px3YqE51nnWswlg_Or0ApUt8aXbXouikvplw_8EmcS1ivx2DduezU6zCOPlf_ilJ56mMp55edttaD4HlMzLHbkWI9y5LDDJVnL5c2fdaFgWf4A9qLCPNoXo3m_HgcmC-F3pmHA1YyZ/s1600/update-book-status-service-spring-initializr.png" style="display: block; padding: 1em 0px; text-align: center;"&gt;&lt;img alt="update -booking-status-service spring initializer project setup" border="0" data-original-height="564" data-original-width="1198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5BwpTO89nBdleoRYPLVTYkvBi_a1u3dm7czNTy50y0WjQhwvQj3Px3YqE51nnWswlg_Or0ApUt8aXbXouikvplw_8EmcS1ivx2DduezU6zCOPlf_ilJ56mMp55edttaD4HlMzLHbkWI9y5LDDJVnL5c2fdaFgWf4A9qLCPNoXo3m_HgcmC-F3pmHA1YyZ/s1600/update-book-status-service-spring-initializr.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Let's utilize Java 8's Consumer Interface to consume messages from the Kafka topic. Because it receives just one argumentase input and does not give any response, the consumer interface is utilized to consume the message.&lt;/p&gt; &lt;br /&gt;

&lt;p&gt;Create a bean called &lt;code&gt;consumeMovieTickedBookingMessage&lt;/code&gt; that we will associate with in the properties file to consume the message from Kafka.&lt;/p&gt;&lt;br /&gt;

&lt;pre&gt;&lt;code class="java"&gt; package in.learnjavaskills.updatebookedstatusservice.function;

 import in.learnjavaskills.updatebookedstatusservice.dto.MovieTicketBookedSuccessfully;
 import in.learnjavaskills.updatebookedstatusservice.repository.MovieTicketRepository;
 import org.apache.kafka.streams.kstream.KStream;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;

 import java.util.function.Consumer;

 @Configuration
 public class MovieTicketBookingConsumer
 {
    private final MovieTicketRepository movieTicketRepository;

    @Autowired
    public MovieTicketBookingConsumer(MovieTicketRepository movieTicketRepository) {
        this.movieTicketRepository = movieTicketRepository;
    }

    @Bean("consumeMovieTickedBookingMessage")
    public Consumer&amp;lt;KStream&amp;lt;String, MovieTicketBookedSuccessfully&amp;gt;&amp;gt; consumeMovieTickedBookingMessage() {
        return movieTicketBookingMessageKStream -&amp;gt; {
          movieTicketBookingMessageKStream.foreach((messageKey, message) -&amp;gt; {
              System.out.println("Message Key : " + messageKey + " Message : " + message.toString());
              // Saving the successfully booked movie ticked into the data base.
              movieTicketRepository.save(message);
          });
        };
    }
 }&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;

&lt;h3&gt;Kafka Broker Configuration in the Update Booked Status Service&lt;/h3&gt;

&lt;pre&gt;&lt;code class="properties"&gt; # application name
 spring.application.name = update-booked-status-service-application

 # broker server node
 spring.cloud.stream.kafka.binder.brokers = 54.146.205.212:9092

 # kafka binder name - method name of your function
 spring.cloud.function.definition = consumeMovieTickedBookingMessage

 # kafka consumer group name
 spring.cloud.stream.bindings.consumeMovieTickedBookingMessage.group = ${spring.application.name}

 # kafka topic name
 spring.cloud.stream.bindings.consumeMovieTickedBookingMessage-in-0.destination = movie-ticket-booked-topic


 # deserialization configuration
 spring.cloud.stream.kafka.bindings.consumeMovieTickedBookingMessage.in-0.consumer.configuration.key.deserializer = org.apache.kafka.common.serialization.StringDeserializer
 spring.cloud.stream.kafka.bindings.consumeMovieTickedBookingMessage.in-0.consumer.configuration.value.deserializer = org.springframework.kafka.support.serializer.JsonDeserializer


 # adding the trusted package to deserialize the JSON data else it will throw to add the trusted package exception
 spring.cloud.stream.kafka.streams.binder.configuration.spring.json.trusted.packages = '*'
 spring.cloud.stream.kafka.streams.binder.configuration.spring.json.use.type.headers = false &lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;

&lt;h3&gt;Dependencies&lt;/h3&gt;

&lt;pre&gt;&lt;code class="groovy"&gt; dependencies {
	implementation 'org.apache.kafka:kafka-streams'
	implementation 'org.springframework.cloud:spring-cloud-stream'
	implementation 'org.springframework.cloud:spring-cloud-stream-binder-kafka-streams'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.cloud:spring-cloud-stream-test-binder'
	// required this dependencies to deserialize java 8 date/time
	implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.16.0'
 }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;


&lt;p&gt;The source code is available on &lt;a href="https://github.com/LearnJavaSkills/spring-cloud-stream-kafka-stream" rel="nofollow" target="_blank"&gt;(getButton) #text=(GitHub) #icon=(download) #color=(#000000)&lt;/a&gt;&lt;/p&gt; &lt;br /&gt;


&lt;h2&gt;Conclussion&lt;/h2&gt;

&lt;p&gt;Spring CLoud Stream 3.0 encourages us to consume or produce messages in the Kafak topic using the functional approach.We covered how to use the Spring Cloud Stream with the Kafka Stream in this presentation.&lt;/p&gt;&lt;br /&gt;

&lt;p&gt;As you can see in this example, I utilized the IP address of the Kafak broker server node, however this is not the best practice. You should always utilize host names rather than IP addresses.&lt;/p&gt;&lt;br /&gt;


&lt;p&gt;&lt;b&gt;Keep learning and keep growing&lt;/b&gt;.&lt;/p&gt;


 





  
  
 

  
  

     
</content><link href="https://www.learnjavaskills.in/feeds/8155081541525664608/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/12/spring-cloud-stream-and-kafka-streams.html#comment-form" rel="replies" title="0 Comments" type="text/html"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/8155081541525664608" rel="edit" type="application/atom+xml"/><link href="https://www.blogger.com/feeds/6877522804921028548/posts/default/8155081541525664608" rel="self" type="application/atom+xml"/><link href="https://www.learnjavaskills.in/2023/12/spring-cloud-stream-and-kafka-streams.html" rel="alternate" title="Spring Cloud Stream and Kafka Streams: The Perfect Duo for Building Event-Driven Architectures | LearnJavaSkills" type="text/html"/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXDxJZ1TgawdEr8lJzNYtSCXLRXbeiDuaaeUuLneevh8Azxkr9wPqzUjrmyA9DwnY3HXZynBU2OTwwOwj4Gc2qZTZdLANhWuzUved0jHstY0x7eul0s_UAV3Vd28Eec8AYYjxN2RgLzFHtz9aLs4ydK81lByxwL4rs04XUMbPDckWlpdBnPl77C8uCb1Tw/s72-c/thumbnail-image.png" width="72"/><thr:total>0</thr:total><georss:featurename>India</georss:featurename><georss:point>20.593684 78.96288</georss:point><georss:box>-7.7165498361788458 43.80663 48.903917836178849 114.11913</georss:box></entry></feed>