Factory Method Pattern for Spring Hateoas Links

Problem Description

You have a single class in your application where you create Hateoas Links for different API versions (e.g.: V1 and V2). The class grows quickly with time as you add a lot of logic for those versions. You want to refactor the existing class so that it is easier to be modified for future development.

Proposed Solution

You can implement the factory method pattern to separate V1 and V2 logic.

  1. Define an interface that holds
    • the common interface methods which have to be implemented by V1 and V2.
    • the default methods that are required for only V1 or V2.
  2. Define HateoasLinksV1 and HateoasLinksV2 classes that implement the common interface.
  3. Define a Factory class that creates V1 or V2 hateoas links depending on the API version.

Define an interface

public interface HateoasLinks {

  // common interface for v1 and v2 versions
  Link getLink(RequestParam requestParam); 
  
  // only for v2 version
  default Function<RequestParam, List<Link>> getLinkForV2() {
    return param -> {
        List<Link> hateoasLinks = new ArrayList<>();
        hateoasLinks.add(setSomeHateoasLinks(param));
        return hateoasLinks;
     };
}

}

Define HateoasLinksV1 and HateoasLinksV2 classes

@Component
public class HateoasLinksV1 implements HateoasLinks {

  @Override
  Link getLink(RequestParam requestParam) { ... }
}

@Component
public class HateoasLinksV2 implements HateoasLinks {

  @Override
  public Link getLink(RequestParam RequestParam) { ... }

  @Override
  public Function<RequestParam, List<Link>> getLinkForV2() {
     return param -> {
        List<Link> hateoasLinks = 
             HateoasLinks.super.getLinkForV2();
        hateoasLinks.add(setSomeHateoasLinks(param));
        return hateoasLinks;
     };
  }

}

Define Factory Class

@Component
public class HateoasLinksFactory {

  public HateoasLinks getInstance(Request request){
    if(StringUtils.equalsIgnoreCase(request.getApiVersion(), Constant.V2)){
      return new HateoasLinksV2();
    }
    return new HateoasLinksV1();
  }

}

Use HateoasLinkFactory Class

public Response createHateoasLink(){
  
  Response response = new Response();
  Link link = hateoasLinksFactory.getInstance(requestParam).getLink();
  response.add(link);

}

Note that Resource class is a ResourceSupport, which is a base class for DTOs to collect links.

@Data
public class Response extends ResourceSupport {
	
	@ApiModelProperty("State")
	private String state;
	
	@ApiModelProperty("Action of the Customer")
	private String action;

}

Leave a Reply

Your email address will not be published. Required fields are marked *