'Spring REST controller with service using proxy pattern

I have created REST controller with base request mapping on class.

@RestController
@RequestMapping(".../{type}/{typeId}/param..")
public class FooController{

  @Autowired
  BarServiceProxy proxy;

  public List<Foo> getFoo(){
  return proxy.get(getType());
  }

/*
  public Type getType(???){
  return type;
 }
*/
}

Next I have enum Type which determines what service will be used by proxy service (ie. proxy has injected list of serivces and gets one that supports type). I am wondering if there is any way how to make part of request mapping {type} and get it in getter method below so I don't have to repeat it in every request mapping in this class.

I only figured one alternative solution - make this class abstract and then extend it and return constant. This would however leave me with lot of classes without any added value. For example:

 @RequestMapping(".../{typeId}/param..")
    public abstract class FooController{
    
      @Autowired
      BarServiceProxy proxy;
    
      public List<Foo> getFoo(){
      return proxy.get(getType());
      }
    
   
      protected abstract Type getType();
    
    }

@RestController
@RequestMapping("/typeAbc)
public class TypeAbcFooController extends FooController{
 
  public Type getType{
   return Type.Abc;
 }

}

So is it possible to bind @PathVariable from URL specified on class @RequestMapping in some shared method? Thanks



Solution 1:[1]

I hope i've understood your problem, but one way of improving your design could be to implement a strategy per type, to inject them, and to use them corresponding to your type received in your controller.

Exemple:

public enum MyType {
    TYPE1,
    TYPE2
}

public interface IService {

    MyType getHandledType();
    List<Foo> getFoo();
}

@Service
public class Type1Service implements IService {

    @Override
    public MyType getHandledType() {
        return MyType.TYPE1;
    }

    @Override
    public List<Foo> getFoo() {
        // IMPLEMENTATION FOR TYPE1;
    }
}

public class FooController{

    @Autowired
    List<IService> services;

    public List<Foo> getFoo(MyType requestType){
        IService service = services.stream().filter(iService -> iService.getHandledType() == requestType).findFirst().get();
        return service.getFoo();
    }
}

This way your controller is agnostic of the underlying service implementation, which is a big responsability.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mickaël B.