Child controller in spring boot - java

Let's imagine a scenario where I have a Spring Boot app (in a controller/service/repository pattern) which contains controller for cars. Now I would like to create paths that look for example like this:
"/api/cars/bmw"
"/api/cars/mercedes"
"/api/cars/audi"
And so on. And for each of these car producers I would like to have multiple endpoints, some of them common for all car producers (not sure if it really matters but just for the sake of it lets say for example "/order" and "/cancelOrder"), but some of them different.
Now what would be the proper way to implement this scenario? Is there a way to make a CarController for the /car/{producer} path which would be a proxy for other controllers like AudiController handling /car/audi requests? Having 3 car producers in one controller and a service for each car producer is ok, but having 30 would make a lot of injected dependencies (30 services injected into the controller) if I would have only one CarController.
I believe node.js Express framework would allow us to do this in the car "controller" script (not sure if they are called controllers in express or what):
var app = express();
app.use('/audi', '{path to audi controller script}');
Is there a similar possibility in Spring? Or is this maybe a bad idea, an antypattern?
Another idea that is quite simple but seems not that elegant is to skip the CarController and implement a:
AudiController with the #RequestMapping("/api/cars/audi")
BmwController with the #RequestMapping("/api/cars/bmw")
MercedesController with the #RequestMapping("/api/cars/mercedes")
etc.
So, what would be the best idea here?

Spring has #PathVariable for this, which can be used in the following way:
#RestController
#RequestMapping("/api/cars/")
public class MyController {
#GetMapping
#RequestMapping("{producer}/cancelOrder")
public String cancelOrder(#PathVariable String producer) {
return "Cancel order for " + producer;
}
}
We can call this endpoint like this: http://localhost:8080/api/cars/Mercedes/cancelOrder
There is no such thing as child controller in Spring. If you want to create a separate controller for every producer having some common functionality, you can use inheritance:
Parent controller class (please note that this does not have any Controller annotation):
#RequestMapping("/api/cars/")
public class BaseCarController {
#GetMapping("/common")
public String common() {
return "Common stuff";
}
}
Child controller classes:
#RestController
public class MercedesController extends BaseCarController{
private MercedesService mercedesService;
// Spring will autowire this by default, no need to add #Autowired
public MercedesController(MercedesService mercedesService) {
this.mercedesService = mercedesService;
}
#GetMapping
#RequestMapping("Mercedes/cancelOrder")
public String cancelOrder() {
return "Cancel order for Mercedes.";
}
}
#RestController
public class AudiController extends BaseCarController{
private AudiService audiService;
// Spring will autowire this by default, no need to add #Autowired
public AudiController(AudiService audiService) {
this.audiService = audiService;
}
#GetMapping
#RequestMapping("Audi/cancelOrder")
public String cancelOrder() {
return "Cancel order for Audi.";
}
}
We can call the produces specific endpoints like this:
http://localhost:8080/api/cars/Mercedes/cancelOrder or http://localhost:8080/api/cars/Audi/cancelOrder. Moreover we can call the common endpoint in the following way: http://localhost:8080/api/cars/common

Related

Spring Boot + Spring Data: Concurrent/parallel save/insert into databases

Small question regarding SpringBoot and SpringData, and how to save a pojo into many databases concurrently, in parallel please.
I have a very simple SpringBoot application which does nothing but expose a rest endpoint to save a pojo:
#RestController
public class SaveController {
#Autowired
MyElasticRepository myElasticRepository;
#Autowired
MyMongoRepository myMongoRepository;
#Autowired
MyAARepository myAARepository;
//#Autowired MyBBRepository, MyCCRepository, ... MyYYRepository
#Autowired
MyZZRepository myZZRepository;
#GetMapping("/saveSequential")
public String saveSequential(#RequestBody MyPojo myPojo) {
MyPojo myPojoFromElastic = myElasticRepository.save(myPojo);
MyPojo myPojoFromMongo = myMongoRepository.save(myPojo);
MyPojo myPojoFromAA = myAARepository.save(myPojo);
// myBBRepository.save(myPojo) myCCRepository.save(myPojo) ... myYYRepository.save(myPojo)
MyPojo myPojoFromZZ = myZZRepository.save(myPojo);
return ...;
}
}
However, the pojo needs to be saved in many databases, by many, imagine a good dozens of different databases.
As of now, as you can see from the code, the pojo is saved in each of the databases sequentially. I timed the application, as well as monitoring the DBs, the inserts come one after another.
Hypothetically, if one save takes one second, and I have 20 DB, the rest endpoints takes 20ish seconds to complete.
Since the operation is not dependent of any others, i.e. saving the pojo in Mongo, has no dependency on the data saved in Oracle, etc... I would like to optimize the performance by doing the operation in parallel.
I.e, if each save takes one second, and I have 20 DBs, to parallel the save, which should still take something like oneish second. (I am exaggerating)
For the sake of the question, let us imagine the machine doing the save has many cores, is a very good machine, etc.
What I tried:
I tried using the #Async annotation on the repository, such as:
#Async
#Repository
public interface MyElasticRepository extends ElasticsearchRepository<MyPojo, String> {
}
But unfortunately, timing the endpoint, it still takes a sequential time.
May I ask how to achieve this parallel, concurrent save please?
If possible, I would like to leverage existing features of Spring Framework, and not having to rewrite boiler plate concurrency code.
Thank you!
I think you are best off creating a service layer with an async method.
import org.springframework.data.repository.Repository;
import java.util.concurrent.CompletableFuture;
import org.springframework.stereotype.Service;
import org.springframework.scheduling.annotation.AsyncResult;
#Service
public class MyPojoPersister {
#Async
#CompletableFuture<MyPojo> savePojo(Repository repo, MyPojo pojo) {
return CompletableFuture.completedFuture(repo.save(pojo));
}
}
Then your controller would look something like this:
#RestController
public class SaveController {
#Autowired
MyElasticRepository myElasticRepository;
#Autowired
MyMongoRepository myMongoRepository;
#Autowired
MyAARepository myAARepository;
//#Autowired MyBBRepository, MyCCRepository, ... MyYYRepository
#Autowired
MyZZRepository myZZRepository;
#Autowired MyPojoPersister myPojoPersister;
#GetMapping("/saveSequential")
public String saveSequential(#RequestBody MyPojo myPojo) {
var futureList = Stream.of(myElasticRepository, myMongoRepository, myAARepository, myZZRepository)
.map(repo -> myPojoPersister.savePojo(repo, myPojo))
.collect(Collectors.toList());
CompletableFuture.allOf(futureList.toArray(new CompletableFuture[list.size()])).join();
var someString = futureList.stream()
.map(CompletableFuture::get())
.map(MyPojo::getId())
.collect(Collectors.joining(","));
return someString;
}
}
I added some assumptions that you want to return a comma separated list of the ids of the pojos since they would presumably be different for each repo. But do whatever you need to with the values of the futures.
Don't forget to enable asynchronicity!
#SpringBootApplication
#EnableAsync
public class MyPojoApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncMethodApplication.class, args).close();
}
}

How to create a dynamic proxy of a already proxyed class in spring

I'm relativly new to spring/spring boot.
At the moment I'm using a spring boot rest application which provides an FeignClient to be included in other projects. Now, I want those FeignClients be wrapped by a CircuitBreaker.
The best solution I came up with, is that I dynamically create a proxy which includes the CircuitBreaker implementation which itself calls the created FeignClient.
So let's assume I have the following interface which describes the RestController:
#RequestMapping("/")
public interface MyWebService {
#GetMapping("name")
public String getName();
}
Now, I have the interface for the FeignClient:
#FeignClient("app")
public interface WebServiceClient extends WebService {
}
So.. My goal would be to achieve something like I have another annotation e. g. #WithCircuitBreaker which I then will be scanned for and dynamically create a proxy bean which will be injected instead of the FeignClient bean.
At the moment my code looks like this:
#FeignClient("app")
#WithCircuitBreaker
public interface WebServiceClient extends WebService {
}
As far as I know, I can now create a #Configuration Class which will look like this:
#Configuration
public class WithCircuitBreakerConfiguration implements ImportAware {
private AnnotationMetadata annotationMetadata;
private AnnotationAttributes annotationAttributes;
#Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.annotationMetadata = importMetadata;
Map<String, Object> annotatedClasses = importMetadata.getAnnotationAttributes(WithCircuitBreaker.class.getName());
this.annotationAttributes = AnnotationAttributes.fromMap(annotatedClasses);
}
What else to import to create the proxy and inject it?
}
Now I'm at the point, which I don't know how to continue. How to dynamically create a proxy class which does something like this:
public class PorxyedWebService {
private WebService feignClientProxy;
#Autowired
public ProxyedWebService(WebService feignClientProxy) {
this.feignClientProxy = feignClientProxy;
}
public String getName() {
...
<some circuitbreaker stuff>
....
return this.feignClientProxy.getName();
}
}
and then return this proxy instead of the proxy generated from Feign as soon as someone autowires the WebService interface.
I am not a Spring user, but I do know that Spring does not create proxies recursively if e.g. multiple Spring AOP aspects are applied to the same object. Instead, additional interceptors (or advices in AOP language) are registered upon the same proxy. I think you want to use that infrastructure in order to achieve whatever your objective is.
You can just use the resilience4j Spring Boot2 starter.
You can combine the #CircuitBreaker annotation with the #FeignClient annotation at interface level.
You can then use it as follows:
#FeignClient(name = DUMMY_FEIGN_CLIENT_NAME)
#CircuitBreaker(name = DUMMY_FEIGN_CLIENT_NAME)
public interface DummyFeignClient {
String DUMMY_FEIGN_CLIENT_NAME = "dummyFeignClient";
#GetMapping(path = "/api/{param}")
void doSomething(#PathVariable(name = "param") String param);
}

node response.end() equivalent in spring

Is there any way in spring that we can send response immediately.
I want to create a thread which will do a job. But I don't want to make the user to wait till that job completed.
There is multiple way of doing so in Spring.
Here is their article.
If you want to make the operations asynchronously, the easiest way is to use the #Asyn annotation from Spring.
Here is a simple example :
// Interface definition for your async operation here
public interface AsyncOperator {
#Async
void launchAsync(String aBody);
}
And a simple implementation that uses the interface
// Need to be a bean managed by Spring to be async
#Component
class SimpleAsync implements AsyncOperator {
#Override
public void launchAsync(String aBody){
// Your async operations here
}
}
Then you need for Spring to configure how the async works. Using Spring boot a simple configuration class like this works:
#Configuration
#EnableAsync
public class AsyncConfiguration {
}
Then you can call your method and it will return right away and do the treatments asynchronously :
#Component
public class AController {
private final AsyncOperator async;
public AController(AsyncOperator async){
this.async = async;
}
public String aMethod(String body){
// here it will return right after call
this.async.launchAsync(body);
return "Returned right away !!";
}
}
The only downsides of this method is that all your classes for async operations must be managed by Spring.

Creating Spring #Repository and #Controller for every item I'm working with(from database)

While working with a project that involves requesting multiple data types from a database I came to a following question:
Lets say I have 2 java classes that correspond to database entities:
Routes
public class Route {
public Route(int n, int region, Date fdate, boolean changed, int points,
int length) {
super();
this.n = n;
this.region = region;
this.fdate = fdate;
this.changed = changed;
this.points = points;
this.length = length;
}
}
Carrier
public class Carrier {
public Carrier(...) {
this.id = src.getId();
this.name = src.getName();
this.instId = src.getInstId();
this.depotId = src.getDepotId();
}
If so, what's the correct approach of creating Dao interfaces and classes? I'm doing it like this -
#Repository
public class CarrierDaoImpl implements CarrierDao{
#Autowired
DataSource dataSource;
public List<Carrier> getAllOrgs() { ... }
}
#Repository
public class RoutesDaoImpl implements RoutesDao {
#Autowired
DataSource dataSource;
public ArrayList<AtmRouteItem> getRoutes(AtmRouteFilter filter) { ... }
}
I'm creating a #Repository DAO for every java class item\db entity and then 2 separate controllers for requests about carriers and routes. Like this:
#RestController
#RequestMapping(path = "/routes")
public class RoutesController {
#Autowired
RoutesDao routesDao;
#GetMapping(value = {"/getRoutes/", "/getRoutes"})
public ArrayList<Route> getRoutes() { ... } }
And same for controller Carriers. Is it correct and if not what's the correct approach?
Sorry for styling issues, that's my first question on stackoverflow :)
I would suggest creating services marked with #Service annotation (i.e. CarrierService interface and CarrierServiceImpl implementation). Than inject them into controllers. Use repositories within services because some database operations will require transactions and a better place for managing transactions are services. Also services can do more specialized job which will require access to multiple repositories so you can inject them. And don’t forget to mark your services with #Transactional annotation.
It's correct to have a DAO for each entity.
When working with JPA repositories you have no choice but to provide the entity. For instance:
public interface FooRepository extends JpaRepository<Foo,Long>{}
Same for the REST controllers, you have to bring together functionalities by object as you do.
You can improve your mapping to be more RESTful. To retrieve all routes, don't specify a path:
#GetMapping
public ArrayList<RouteResource> getRoutes() { ... }
(I never use #GetMapping yet but it should work like that)
And if you want specific route:
#GetMapping("/get/{id}")
public RouteResource getRoute() {...}
You should return resources instead of entities to client.

Is it possible to nest controllers/have controllers as inner classes in Spring 4 MVC?

I want to have a controller that maps to /site/ and within that two different controllers to look something like:
#Controller
#RequestMapping(value="/api")
public class ApiController {
#Controller
#RequestMapping(value="/foo")
public class FooController {
//Some /foo/* methods here
}
#Controller
#RequestMapping(value="/bar")
public class BarController {
//Some /bar/* methods here
}
//Other methods that don't match /foo or /bar
}
Is this okay or would be it be better practice to split it up into two separate controllers with /site/foo and /site/bar mappings?
You should be using methods and not classes for the mappings. The code should be written like this
#Controller
#RequestMapping(value="/site")
public class ApiController {
#RequestMapping(value="/foo", method=RequestMethod.GET)
public String doFoo {
// Foo Logic
return "Running Foo";
}
#RequestMapping(value="/bar", method=RequestMethod.GET)
public String doBar {
// Bar Logic
return "Running Bar";
}
}
Tying your class hierarchy to your resource hierarchy should not be the main design driver here.
IN Spring MVC, Controllers are simple POJOs to make them easy to test, composition is favored over inheritance, annotations are used to convey meaning and make your code more readable.
Nesting Controllers under Controllers defeats several of those goals.

Categories