Showing posts with label Spring. Show all posts
Showing posts with label Spring. 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


14/05/2017

[Java] Xchange me, sir - Sample REST project to get xrates to EUR

Project description Xchange me, sir:

Implement a simple foreign exchange rate service that uses data provided by the European Central Bank. Provide a REST API to retrieve the exchange rate to EUR from any other currency provided by the ECB and allow querying current (https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml) and past (https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml) data. Use an asynchronous job to retrieve and update the xrates storing them locally in memory and have the REST API use the data in memory to return this information.

01/11/2015

[Java Spring] Plan my Groove

Plan my Groove is a simple Java7+ application to expose a REST API to let users remotely execute Groovy scripts

It was tested on both JDK7 and JDK8 and as of now it exposes functionality to:


  • submit a job
  • list and search for jobs
  • retrieve the result of a job
  • delete a job


Where a job is a simple Groovy script. It's possible to submit multiple jobs simultaneously and also run them at the same time.

It relies heavily on the RepositoryRestResource functionality offered by the Spring framework to provide a set of RESTful services.

Find the source code at https://github.com/steghio/PlanMyGroove and for more information, read the documentation at https://github.com/steghio/PlanMyGroove/blob/master/plan_my_groove_manual.pdf

06/06/2015

[OSGi] Spring error Unable to locate Spring NamespaceHandler for XML schema namespace

You're working with OSGi because it's flexible, you like components, and so on, and you also like Spring because you love writing XMLs instead of Java code.

You think it would be a good idea if you could join these technologies but reading is so boring, plus since both use some config files you just need to mash them together and you should be good with your Sprosgienstein creation. But then you realize that some small differences for example in classpath handling and dependency management are making your life difficult.

A common error you might get is: "Unable to locate Spring NamespaceHandler for XML schema namespace XXX"

12/10/2013

[Java] Keep HTML form filled after failed Spring validation

I was working on a JSR-168 portlet written in Java 4 using Spring 2 and I had plain HTML forms validated via Spring validators. Everything works fine with this setting but upon failed validation, the page would reload showing the errors and an empty form.

Instead of replacing all the forms with Spring ones (form:form), I found an alternative solution which let me keep my current project structure and tone down the necessary modifications.

08/10/2013

[Java] Store session attributes in portlet controller and retrieve them from JSP

I was coding a portlet following the JSR-168 specification and Spring 2 and I noticed an inconsistent behaviour on some pages. Passing some Map objects, needed to initialize the JSP drop-down menus, by storing them in session in the controller and retrieving them in the JSP, would work always except when the page was reloaded after a failed form validation during the submission phase.

Note: this issue could not be solved by simply using the ModelAndView addObject("name", value) method in the controller and then retrieving the object in the JSP with ${name} outside of a Java block, since I needed to perform some actions on those values directly from the JSP, therefore inside a Java block, without using EL.

25/09/2013

[Java] Spring use DAO in JSP page

So you're happily coding your webapp with Spring, and have all your DAOs correctly defined as beans; you know they work because you are constantly injecting them around, but now you need to access one of them from a JSP.. how?

You may find this code fragment useful:

 <%@page import="com.groglogs.mydaos.MyDao"%>  
 <%@page import="org.springframework.web.context.WebApplicationContext"%>  
 <%@page import="org.springframework.web.context.support.WebApplicationContextUtils"%>  
   
 <%  
 MyDao myDao = null;  
   
 WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());  
 if (context != null) {  
   myDao = (MyDao) context.getBean("myDao");  
 }  
 %>  

You import your DAO, and request it directly from the JSP. Note that this example relies on the fact that somewhere you have correctly defined a bean named "myDao".

28/07/2013

[Java 4] Download file from portlet

Scenario: Java 4, Spring 2, WebSphere 6, JSR-168. How the hell do I let the user download a file from a portlet?

The file is extracted from a database and does not exist on the server's filesystem yet; redirecting to a servlet to create and send the response which contains the file to download fails with a generic:

java.lang.IllegalStateException: Can't invoke sendRedirect() after certain methods have been called

More specifically, that method can not be invoked after any of the following methods of the ActionResponse interface has been called:
  •         setPortletMode
  •         setWindowState
  •         setRenderParameter
  •         setRenderParameters
  •         removePublicRenderParamter
And currently I don't know whether it's Spring or WebSphere calling one of those forbidden methods silently.