Showing posts with label Spring Boot. Show all posts
Showing posts with label Spring Boot. Show all posts

26/09/2024

[Java] Using annotation processing (and validating it) to execute logic at runtime

Sample project showcasing how to use annotations to perform runtime logic to log changes in object values.

Remember it is a SAMPLE, so obviously (lazy me) most null-safe checks and so are not included and obviously some logic is a showcase, should be replaced with a real business scenario to implement.

In this SAMPLE, we tag fields to be included in a diff logic to then print to output when those fields values change by comparing two instances of the same object.

Logic can obviously be made much more complex including collections and maps and whatnot (Java Generics are your friends there).

Also worth mentioning JaVers can do most of it for you, unless you have fancy business requirements that force you to write custom code..


Key points:

- How to create an annotation

- How to create an annotation processor to validate the annotation parameters at compile time

- How to register an annotation processor

- How to configure a multi-module Maven project to use a custom annotation processor (also, in the pom of the root project ensure the module containing the processor is built BEFORE everything else)

- How to test an annotation processor by generating classes at runtime and trigger compilation tasks agains them. Includes verifying compilation warnings are properly triggered as expected.

- How to use reflection to get fields annotated with a given annotation (and then execute whatever logic on them)

- How to use reflection to invoke methods (including static methods)


The full project is available on my GitHub repo with commented code: https://github.com/steghio/diff-annotation-processing

30/08/2023

[Spring] Synchronized methods and separate transactions

When marking a method as synchronized, it's important to remember that synchronization does NOT change the transactionality settings of the current operation.

For example the following parallel execution:

methodA() calls syncMethod() then calls somethingElse()
methodB() calls syncMethod() then calls somethingElse()

What happens:
  1. methodA opens Transaction A enters syncMethod
  2. methodB opens Transaction B waits on syncMethod
  3. methodA exits syncMethod, starts executing somethingElse
  4. methodB enters syncMethod while methodA completes somethingElse and commits Transaction A
  5. methodB exits syncMethod, starts executing somethingElse
  6. methodB completes somethingElse and commits Transaction B

Now the important part is points 4. If the syncMethod requires fresh data from other executions, methodB will NOT see that data when it enters syncMethod since Transaction A has NOT yet been commited.

The synchronization is only blocking a thread from entering the protected code block, but as soon as the resource is free, the next waiting thread will enter immediately.

This means that to allow other methods to read latest data while in the protected section, any operation done in the synchronized method must be executed in a separate transaction, for example using the TransactionHandler helper.

09/08/2023

[Spring] Execute method in separate transaction

In Spring annotating a method as requiring a new transaction will not work if the caller of the method is in the same class.

We can easily work around this issue by creating a new class that will execute a given method in a new transaction:

 import org.springframework.stereotype.Service;  
 import org.springframework.transaction.annotation.Propagation;  
 import org.springframework.transaction.annotation.Transactional;  
   
 import java.util.function.Supplier;  
   
 /**  
  * Since spring ignores transaction settings for methods within the same class, we need a separate service  
  * to run isolated transactions which can be called from anywhere simply by supplying the method to execute  
  */  
 @Service  
 public class TransactionHandlerService {  
   
   /**  
    * Runs the given method in a the same transaction as the caller  
    *  
    * @param supplier the method to execute  
    * @param <T>  
    * @return the result of the invoked method  
    */  
   @Transactional(propagation = Propagation.REQUIRED)  
   public <T> T runInSameTransaction(Supplier<T> supplier) {  
     return supplier.get();  
   }  
   
   /**  
    * Runs the given method in a separate transaction  
    *  
    * @param supplier the method to execute  
    * @param <T>  
    * @return the result of the invoked method  
    */  
   @Transactional(propagation = Propagation.REQUIRES_NEW)  
   public <T> T runInNewTransaction(Supplier<T> supplier) {  
     return supplier.get();  
   }  
 }  

Then ensure the callers are annotated as @Transactional and simply pass the method to execute as input to our, for example:

transactionHandlerService.runInNewTransaction(() -> myMethod(someInput));

13/03/2020

[Java] Schedule tasks with Quartz and Spring

We saw how to schedule tasks with ScheduledExecutorService, and we now we will see how to achieve the same result using the Quartz framework.

Much like before, we have two key concepts:
  • job: a job is a runnable class that implements the Job interface
  • trigger: a Trigger is a specific schedule for a job. A trigger can only be linked to a job, and a job can be linked to multiple triggers.
You can find Quartz on Maven.

22/08/2019

[Spring] Schedule tasks

Scheduling execution of tasks in Spring is quite easy and requires just a couple annotations:

  • Annotate the application class with @EnableScheduling
  • Provide an @Component annotated class which includes the methods to be scheduled, each annotated with @Schedule 
The schedule itself can be passed as a property. 

27/04/2019

[Spring Boot] Configure CORS

CORS (Cross-origin resource sharing) is an important security aspect of modern web applications. To prevent malicious content from being pulled into your page, usually the source(s) of the content for it are restricted to prevent external domains from serving pieces of your final page.
This functionality goes along with CSRFX-Frame-Options, SessionPolicy and SecurityHeaders to provide a complete setup for your application.

All of this can be however very easily configured in Spring version 4+ (and therefore Spring Boot 2 as well) by providing a custom SecurityConfig (WebSecurityConfigurerAdapter) that will prevent Spring Boot from autoconfiguring the security with its own defaults.

Here is a sample implementation for Spring Boot 2 that completely disables (allows everything) CORS, it comes from this StackOverflow, slightly modified:

[Spring Boot] Upload file

In Spring Boot 2, your controller can expose a POST method to accept a file upload and return a JSON response simply as such:

 @RequestMapping(value="/upload", method=RequestMethod.POST, consumes = {"multipart/form-data"}, produces=MediaType.APPLICATION_JSON_VALUE)  
 @Transactional  
 public ResponseEntity<String> uploadFile(@ModelAttribute FileUploadRequest fileUploadRequest) {  
   
  fileUploadRequest.getFile(); //@TODO do something with your file  
   
  return new ResponseEntity<String>("{\"result\":\"success\"}", HttpStatus.OK);  
 }  
   
   
   
 @InitBinder  
 protected void initBinder(HttpServletRequest request,  
              ServletRequestDataBinder binder)   
 throws ServletException {  
  binder.registerCustomEditor(byte[].class,  
                new ByteArrayMultipartFileEditor());  
 }  


And the FileUploadRequest class looks something like this:

 @Accessors(chain = true)  
 @AllArgsConstructor  
 @NoArgsConstructor  
 public class FileUploadRequest {  
   private String fileName;  
   private byte[] file;  
 }  


With all the magic annotations coming from Lombok, Gradle configuration will look like this:

annotationProcessor "org.projectlombok:lombok:VERSION"
compileOnly "org.projectlombok:lombok:VERSION"

[Spring Boot] Download or display file in browser from controller

In Spring Boot 2, we can provide an endpoint that allows users to perform GET requests to download (or display) a file in their browsers as follows:

 @RequestMapping("/downloadFile/{fileId}")  
 public ResponseEntity<byte[]> downloadFile(@PathVariable("fileId") String fileId){  
  File file = null; //@TODO get your file from wherever using fileId or the logic you need  
   
  byte[] fileBytes = Files.readAllBytes(file.toPath()); //@TODO for example, but you might convert file to byte[] as you wish  
   
  HttpHeaders headers = new HttpHeaders();  
  headers.setContentType(MediaType.APPLICATION_PDF); //@TODO change accordingly!  
  headers.setContentDispositionFormData("attachment", file.getName()); //change to "inline" if you wish the browser to try do display it instead of downloading. WARNING: behaviour is browser dependent!  
  headers.setCacheControl("must-revalidate, post-check=0, pre-check=0"); //prevent caching  
  ResponseEntity<byte[]> response = new ResponseEntity<>(fileBytes, headers, HttpStatus.OK);  
  return response;  
 }  
   
   
   
 @InitBinder  
 protected void initBinder(HttpServletRequest request,  
              ServletRequestDataBinder binder)   
 throws ServletException {  
  binder.registerCustomEditor(byte[].class,  
                new ByteArrayMultipartFileEditor());  
 }  

[Spring Boot] Send HTML email with attachment using Thymeleaf template

Thymeleaf provides a powerful and easy to use template engine that is effortlessly integrated in Spring and Spring Boot projects.

In this example we look at how to send HTML emails with attachments using a Thymeleaf template from a Spring Boot 2 project.

First of all these are the imports we need to add:

org.springframework.boot:spring-boot-starter-mail
org.springframework.boot:spring-boot-starter-thymeleaf