Restful Service without using Annotations in Spring - spring

I am trying to invoke the Restful Web services using Spring. I searched a lot and was able to make a restful service using different annotations.
Here is a piece of code : -
#Controller #RequestMapping("/service/")
public class RestService {
long currentId = 123;
public RestService() {
}
#ResponseBody
#RequestMapping(value="/get/{id}")
public Rest getRest(#PathVariable("id") String id) {
System.out.println("----invoking getRest, Rest id is: " + id);
Rest c = new Rest();
long idNumber = Long.parseLong(id);
c.setId(idNumber);
c.setName("John");
c.setAge("12.6");
return c;
}
I had a web.xml + (name)-servlet.xml
Above example has just one method and that method is mapped to a url.
Now what I want is not to use annotations at all in a java class. So, is there a way to make rest services without using annotations? How can I configure all the annotations in an XML file and their (all methods in a java class) corresponding URL's?

Related

#RestController over interface + spring

I accidentally found this technique of using RestController annotation.
(I saw this not on the internet, but in one of the examples that I was shown. I couldn't find it on the internet)
#RestController
#RequestMapping("api/user/point")
public interface ExampleRestController {
#PostMapping("{key}" )
#Operation(summary = "Manage...",
description = "Allow user ...")
public HttpStatus changePoints(
#PathVariable
#NotBlank
#Parameter(description = "Id user") String key,
#RequestParam("point")
#Min(0) #Parameter(description = "count something..", required = true) Long point,
#RequestParam("type")
#Parameter(description = "Type of...", required = true) TypeOperation type
);
}
What is this technique, who knows ?
I've seen the Rest Api just like this. Can Spring also dynamically create an endpoint method in the RestController, as it does when executing ...extend CrudRepository ? And how does AOP work in this case ? After all, in order for the bean to be configured, we need to put the annotation above the class (like how it is done at the service level), if you put it above the interface, the full automatic configuration of the bean is not guaranteed
It is spring-interface-driven-controllers.
This is new feature of Spring MVC. ( starting with Spring 5.1)

Spring how to resolve entity uri in #RepositoryRestController

I'm using Spring boot 1.5.3, Spring Data REST, Spring HATEOAS. Spring Data REST is amazing and does a perfect job, but sometimes it's needed custom business logic and therfore I need to create a custom controller.
I'm going to use a #RepositoryRestController to benefit of Spring Data REST functionality (http://docs.spring.io/spring-data/rest/docs/current/reference/html/#customizing-sdr.overriding-sdr-response-handlers).
Because Spring Data REST use HATEOAS by default, I'm using that. I need a controller like this:
#RepositoryRestController
#RequestMapping(path = "/api/v1/workSessions")
public class WorkSessionController {
#Autowired
private EntityLinks entityLinks;
#Autowired
private WorkSessionRepository workSessionRepository;
#Autowired
private UserRepository userRepository;
#PreAuthorize("isAuthenticated()")
#RequestMapping(method = RequestMethod.POST, path = "/start")
public ResponseEntity<?> start(#RequestBody(required = true) CheckPoint checkPoint) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (checkPoint == null) {
throw new RuntimeException("Checkpoint cannot be empty");
}
if (workSessionRepository.findByAgentUsernameAndEndDateIsNull(auth.getName()).size() > 0) {
// TODO return exception
throw new RuntimeException("Exist a open work session for the user {0}");
}
// ...otherwise it's opened a new work session
WorkSession workSession = new WorkSession();
workSession.setAgent(userRepository.findByUsername(auth.getName()));
workSession.setCheckPoint(checkPoint);
workSession = workSessionRepository.save(workSession);
Resource<WorkSession> resource = new Resource<>(workSession);
resource.add(entityLinks.linkFor(WorkSession.class).slash(workSession.getId()).withSelfRel());
return ResponseEntity.ok(resource);
}
}
Because the parameter CheckPoint must be an existant resource, I want the client send the link of the resourse (like you can do in Spring Data REST POST methods).
Unfortunately when I try to do that, server side I receive an empty CheckPoint object.
I already read Resolving entity URI in custom controller (Spring HATEOAS) and converting URI to entity with custom controller in spring data rest? and expecially Accepting a Spring Data REST URI in custom controller.
I'm wondering if there is a best practice to do this avoiding to expose id to the client, followind so the HATEOAS principles.
Try to change you controller like this:
#RepositoryRestController
#RequestMapping(path = "/checkPoints")
public class CheckPointController {
//...
#Transactional
#PostMapping("/{id}/start")
public ResponseEntity<?> startWorkSession(#PathVariable("id") CheckPoint checkPoint) {
//...
}
}
That will mean: "For CheckPoint with given ID start new WorkSession".
Your POST request will be like: localhost:8080/api/v1/checkPoints/1/start.

Custom nested actuator endpoint

Using Spring Boot 1.0, I was able to customize the actuator endpoints as follows...
endpoints.beans.id=foo/springbeans
This would expose the spring beans endpoint at /foo/springbeans. However, in the latest Spring Boot this is not possible due to the following code in the AbstractEndpoint...
#NotNull
#Pattern(regexp = "\\w+", message = "ID must only contains letters, numbers and '_'")
private String id;
I tried using the underscore, but that just exposes the endpoint at /foo_springbeans. This lead me to try to add a view controller so I could at least redirect or forward to the default endpoint, but I couldn't find an easy way to do that either. How can I configure the endpoint or a redirect?
After opening an issue with Spring Boot and being told to simply move the entire management context as suggested by Rafal, I was able to achieve what I was looking for, albeit with more code than I'd like. I created a custom MvcEndpoint as follows...
#Named
public class MyCustomHealthCheck extends EndpointMvcAdapter {
private HealthEndpoint delegate;
#Inject
public MyCustomHealthCheck(HealthEndpoint delegate) {
super(delegate);
this.delegate = delegate;
}
#ResponseBody
#RequestMapping(value = "/springbeans", method = GET)
public Health foo() {
return delegate.invoke();
}
}
The code above creates the /springbeans path underwhatever path the HealthEndpoint is mapped to, which is fine enough for my usecase. If I wanted it mapped to an entirely separate path, I would have needed to create a dummy endpoint and stick this MvcEndpoint under that.
For Spring 1.x Following property should help you:
endpoints.beans.path: /foo/springbeans
You can use it with any standard endpoint and if you want to use it with custom endpoint that extends AbstractEndpoint then you need additional annotation:
#ConfigurationProperties(prefix = "endpoints.customEndpoint")
and then use property:
endpoints.customEndpoint.path: /custom/endpoint

spring mvc 3 caching example

I have requirement for spring mvc 3 caching. Requirement is : while starting the server, we need to call database for one dropdown and put those values in the cache. So that whenever we required those values, we need to retrieve from cache.
Please help me with an example.
Thanks in advance.
May be you can use init-method (Spring 2.5) or #PostConstruct annotation (in Spring 3.0).
This method will be called during server start up
The following is code snippet
#Component
public class CacheDBData {
private String values[];
//add setter & getter
//This will be called during server start up after properties are initialised
#PostConstruct
public void getDataFromDB() {
values = //Logic to get data from DB and store that in values property
}
}
Suppose for example you can use in class as follows
#controller
public class HomeController {
#Autowired
private CacheDBData cacheDBData ;
//getter and setters
private void methodxyz() {
String values[] = cacheDBData.getValues();
}
}
I've had success with Ehcahe for Spring. There's a couple of config files to setup but after that you simply annotate the methods you want to cache the output from and it just works.
This has the advantage that you can change the values coming back from the service/database and NOT have to restart your app, unlike the accepted answer.

How to get Spring MVC #PathVariable without using an annotation?

Given the spring mvc method like the one below.
#RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(#PathVariable("ownerId", int ownerId,
#PathVariable("petId") int petid) {
}
Is there some way to write the method so that all the URI templates variables are passed in as a
map to the handler? something along the lines of ?
#RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(Map<String,Object> allPathVariables) {
Integer ownerId = allPathVariables.get("ownerId");
Integer petId = allPathVariables.get("petId");
}
Is there a way to put all the URI templates in a Map that is passed to a handler method?
Looks like this can't be done with Spring MVC 3.1 there is an issue for it on the spring JIRA which is marked fixed for Spring MVC 3.2 https://jira.springsource.org/browse/SPR-9289

Resources