Restlet path param does not work - java

Below is my routing
public Restlet createInboundRoot(){
Router router = new Router(getContext());
router.attach("account/profile",UserProfile.class);
Following is the Resource class UserProfile.java
#post
#path("add")
public void addUser(User user){
#post
#path("modify")
public void modifyUser(User user){
#post
public void test(){//only this is called
I want to invoke one resource class and do couple of identical functions for a resource class. That means, my above resource class handles functions related to the UserProfiles such as add, modify.
URL are:
account/profile/add => to add a user
account/profile/modify => to modify a user
anyway, above my implementation doesn't work as only the test() method can be invoked through account/profile/
I tried with Pathparams as well.But it also didnot work.
For path params:
router.attach("account/profile/{action}",UserProfile.class);
was added and in the resource class,
#post
#path("{action}")
public void addUser(#pathparam("action") String action, User user){
Anyone tell me where is my problem.

The way you attach your UserProfile server resource is a bit strange. I think that you mixed the native routing of Restlet and the one from the JAXRS extension.
I made some tests regarding your use case and I was able to have the behavior you expect. I used the version 2.3.5 of Restlet.
Here is what I did:
Since you want to use JAXRS, you need to create a JaxRsApplication and attach it on the component:
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8182);
// JAXRS application
JaxRsApplication application
= new JaxRsApplication(component.getContext());
application.add(new MyApplication());
// Attachment
component.getDefaultHost().attachDefault(application);
// Start
component.start();
The application simply list the server resources you want to use but doesn't define routing and paths:
import javax.ws.rs.core.Application;
public class MyApplication extends Application {
public Set<Class<?>> getClasses() {
Set<Class<?>> rrcs = new HashSet<Class<?>>();
rrcs.add(AccountProfileServerResource.class);
return rrcs;
}
}
The server resource defines handling methods and associated routes:
import javax.ws.rs.POST;
import javax.ws.rs.Path;
#Path("account/profile/")
public class AccountProfileServerResource {
#POST
#Path("add")
public User addUser(User user) {
System.out.println(">> addUser");
return user;
}
#POST
#Path("modify")
public User modifyUser(User user) {
System.out.println(">> modifyUser");
return user;
}
#POST
public void test() {
System.out.println(">> test");
}
}
When I call the different paths, right methods are called:
http://localhost:8182/account/profile/modify: the modifyUser method is called
http://localhost:8182/account/profile/add: the addUser method is called
http://localhost:8182/account/profile/: the test method is called
Hope it helps you,
Thierry

Related

Spring boot & maven: use custom url path for backend results in whitelabel error

I have two seperate projects, a projectApi (spring backend) and a projectUi (angular frontent).
I'm using maven-resource-plugin to combine them into one jar for production.
When I start the spring server, the connection between those two modules works fine.
Now I would like to customize the backend url path, so that a request like 'http://localhost:8088/login' looks like 'http://localhost:8088 /api/v1/login'.
I was able to do so, by adding the following entry to application.properties: spring.mvc.servlet-path=/api/v1 and modifying the base url, for calls from the ui to the api.
Since that change I'm getting a whitelabel error calling the ui (localhost:8088).
After some search, I tried to implement WebMvcConfigurer but it did not work for me. This is the reference stackoverflow link.
// Application.java
#SpringBootApplication
#EnableJpaRepositories
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// UserRestService.java
#RestController
#RequestMapping("/user")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class UserRestService extends AbstractRestService {
...
#PostMapping("/login")
public String login(#RequestBody User user) throws CustomException {
return Response.ok(userService.loginUser(user, response));
}
}
// application.properties
server.port=8088
// without that entry the post request works fine -> localhost:8088/user/login
// adding that entry and trying to call: localhost:8088/api/v1/user/login i get whitelabel error
spring.mvc.servlet.path=/api/v1
Try to add "/api/v1/" to your controller otherwise all your controllers will be prefixed by that path and you will not be able to provide other versions withing the same application.
I would prefer to program to an interface. This helps in making better use of IOC. Add the URI prefix (/api/v1/) to the interface like below. It will append this prefix to all methods offered by the interface.
// Interface for UserRestService with URI prefix mentioned using Request mapping annotation
#RequestMapping(value = "/api/certs/", produces = { "application/json" },consumes = { "application/json" })
public interface IUserRestService {
String login(User user) throws CustomException;
}
//UserRestService Class
#RestController
#RequestMapping("/user", method = RequestMethod.POST)
public class UserRestService extends AbstractRestService implements IUserRestService{
...
#PostMapping("/login")
public String login(#RequestBody User user) throws CustomException {
return Response.ok(userService.loginUser(user, response));
}
}

Overriding specific resource in REST API

I have a particular scenario where I have a rest resource having some methods with their path.
My requirement is to create a new resource which will extend the above resource and I want to override only a specific method and want to call rest methods from the parent API only.
For example -
#Path("/data")
public class AResource {
#GET
#Path("/login")
public Response login()
{
//login code
}
#GET
#Path("/logout")
public Response logout()
{
//logout code
}
}
#Path("/data")
public class BResource extends AResource {
#GET
#Path("/login")
#Override
public Response login()
{
//login code modified as per requirement
}
}
I tried this, But its still calling parent class methods only for both the methods.
Is there any alternative to this, please suggest.
Thanks in advance!!!!!!!!!!!

No server side events returned

i am trying to implement server side events.
I have very simple resource exposed by a RESTful web service with Jersey/Grizzly. I try to broadcast the events with the SseBroadcaster. An event is created, whenever a data item comes in and is added to an internal list. A client should open a connection to the URL /events to receive the events.
#Path("sensordataelements")
public class SensorDataResource {
private SseBroadcaster broadcaster = new SseBroadcaster();
#GET
#Path("events")
#Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput getServerSentEvents() {
final EventOutput eventOutput = new EventOutput();
broadcaster.add(eventOutput);
return eventOutput;
}
#POST
#Path("/addraw")
#Produces(MediaType.APPLICATION_JSON)
public Response addRawSensorData(String elementBody) {
... data processing stuff ...
cList.add(
new SensorDataElement.SensorDataElementBuilder().id()
.sensorReading(tmpValue)
.build()
);
OutboundEvent evt = new OutboundEvent.Builder()
.data(Float.class, Float.valueOf(tmpValue))
.build();
broadcaster.broadcast(evt);
return Response.status(201).build();
}
...
I tried to connect with
curl -v http://localhost:8080/sensordataapp/sensordataelements/events
The connection is fine, but i do not get any events. I looked at some examples, but got the impression that this should work. What did i miss?
Thanks!
By default, a new instance of the resource class is created for each request. This means that a new broadcaster is created for each request, which isn't what you want. If you want to make the resource class a Singleton, you can simply annotate the class with #Singleton
#Singleton
#Path("sensordataelements")
public class SensorDataResource {
...
}
Now, only one instance of the resource class will be created for the entire application, and it will be shared for all requests.
The other option, is if you inject the broadcaster, instead of instantiating it yourself, you can inject it as a Singleton. Whether or not the resource class is a singleton or not, it will still get injected the same broadcaster instance. To do that, you can do something like the following in your ResourceConfig subclass
public class AppConfig extends ResourceConfig {
public AppConfig() {
register(new AbstractBinder() {
#Override
public void configure() {
bind(new SseBroadcaster()).to(SseBroadcaster.class);
}
});
}
}
Then in your resource class, just inject it
#Path("sensordataelements")
public class SensorDataResource {
#Inject
private SseBroadcaster broadcaster;
See also:
Dependency injection with Jersey 2.0

How to read session value in Service layer when the value was saved in Play controller

I am using Play 2.4. I have a controller which extends play.mvc.Controller. There I am setting user object in session as below:
session("username", user);
Now I want to read this session object in my service class which doesn't extend play.mvc.Controller, am not getting how I can read this, so please assist.
It is possible by using the Http.Context class:
import play.mvc.Http;
class Service {
public void something() {
String username = Http.Context.current().session().get("username");
// do something
}
}
But, should you? It is very unusual that a layer that is below (service) know things about the layer above (controllers). The code above is harder to test, per instance. Why not rewrite it so that your service receives what it needs from the above layer?
class Service {
public void something(String username) {
// do something
}
}
And your controller will do:
class MyController extends Controller {
public Result action() {
String username = session("username");
service.something(username);
}
}

spring application can't find mapped view

In my spring application, I have one generic controller class with serve as base class for several other controllers in my application. These derived controllers have this structure:
#Controller
#RequestMapping(value="usuario")
public class UsuarioController extends controller<Usuario> {
public UsuarioController() {
super(Usuario.class);
}
}
I will have one of this for each entity class from my application. In the generic controller, I have two methods for each action (ie.: insert, update, delete, select). this two methods (and the generic controller) have this form:
public class controller<E> {
#Autowired
private service<E> serv;
private final Class<E> entityClass;
#RequestMapping(value="cadastra")
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.this.name)")
public ModelAndView cadastra() throws InstantiationException, IllegalAccessException {
return new ModelAndView("privado/"+this.entityClass.getName()+"/cadastra", "command", this.entityClass.newInstance());
}
#RequestMapping(value="cadastra", method=RequestMethod.POST)
#ResponseBody
public String cadastra(#ModelAttribute("object") E object, BindingResult result) {
if(serv.cadastra(object))
return "yes";
else
return "not";
}
}
The problem is that when I run the application, and try access the view mapped by this method, I am getting a 404 error.
Anyone can tell what I am doing wrong here?
The problem is that Spring cannot locate the correct JSP to forward the processing. After reviewing your code it seems that you need to change this.entityClass.getName() with this.getName()

Categories

Resources