Im facing isssue in getting Jersey Generic List in client response. I need to get it as Entity for some reason.
#XmlRootElement(name="list")
#XmlSeeAlso({RESTDomain.class})
public class JAXBContainer<T> {
private List<T> items = new ArrayList<T>();
public JAXBContainer() { }
public JAXBContainer(List<T> items) {
this.items = items;
}
#XmlElementWrapper(name="items")
#XmlAnyElement(lax=true)
public List<T> getItems() {
return items;
}
public void setItems(List<T> items) {
this.items = items;
}
#XmlAttribute
public int getItemsSize() {
return this.items.size();
}
above is my Generic List to the resopnse
#GET
#Produces({MediaType.APPLICATION_XML})
public Response getREST(){
RESTDomain domain = new RESTDomain();
domain.setName("Adams");
domain.setPlace("Zurich");
List<RESTDomain> restDomains = new ArrayList<RESTDomain>();
restDomains.add(domain);
JAXBContainer<RESTDomain> jAXBContainer= new JAXBContainer<RESTDomain>(restDomains);
GenericEntity<JAXBContainer<RESTDomain>> genericEntity = new GenericEntity<JAXBContainer<RESTDomain>>(jAXBContainer){};
return Response.ok(genericEntity).build();
}
Im returning the container with genericEntity. I know with just List inside genericEntity i can get my Entity at my client but the problem is i need to Use my JAXBContainer for some reason.
#Test
public void restGet() throws JAXBException{
ClientConfig cc = new DefaultClientConfig();
client = Client.create(cc);
String baseURI ="http://localhost:3555/SampleREST/rest/sample";
WebResource webResource = client.resource(baseURI);
JAXBContainer<RESTDomain> jAXBContainer= webResource.get(new GenericType<JAXBContainer<RESTDomain>>(){});
System.out.println("response:: "+jAXBContainer.getItemsSize());
}
My problem is im getting the response as JAXBContainer with GenericType as desired but the size of container is 0. What am i missing here? do i have to Use any marshalling and unmarshalling Mechanisms.
But When i request this URI in browser i get the well formed XML, But it fails in client or do we have any other ways to extract entity in client. Thanks in advance
I don't see that you're setting the accept content type anywhere on the client.
Try with: webResource.accept("application/xml")
Related
In my Micronaut app I have a simple REST controller:
public class Response {
private String code;
public Response(String code) {
this.code = code;
}
}
#Controller("/api/test")
public class TestController {
#Post("/")
public Response index() {
return new Response("OK");
}
}
How can I tests this edpoint? I tried using
#MicronautTest
public class TestControllerTest {
#Inject
EmbeddedServer server;
#Inject
#Client("/")
HttpClient client;
#Test
void testResponse() {
String response = client.toBlocking()
.retrieve(HttpRequest.POST("/api/test/")); // FIXME `HttpRequest.POST` requires body
assertEquals("{\"code\": \"OK\"}", response);
}
but HttpRequest.POST requires an additional body argument to be specified. In my case there is no body to be sent. (In the real code it is a request to initialize a new object and thus it has to be POST).
Usually, when you implement a POST action, you expect that there is a body sent with the request. In your example, you don't accept any POST body, but you still need to pass anything in the unit test.
You can instantiate the HttpRequest object in the following way:
HttpRequest.POST("/api/test/", "");
You can't pass null, it has to be some non-null value (like an empty string.)
I have a REST endpoint implemented with Spring MVC #RestController. Sometime, depends on input parameters in my controller I need to send http redirect on client.
Is it possible with Spring MVC #RestController and if so, could you please show an example ?
Add an HttpServletResponse parameter to your Handler Method then call response.sendRedirect("some-url");
Something like:
#RestController
public class FooController {
#RequestMapping("/foo")
void handleFoo(HttpServletResponse response) throws IOException {
response.sendRedirect("some-url");
}
}
To avoid any direct dependency on HttpServletRequest or HttpServletResponse I suggest a "pure Spring" implementation returning a ResponseEntity like this:
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create(newUrl));
return new ResponseEntity<>(headers, HttpStatus.MOVED_PERMANENTLY);
If your method always returns a redirect, use ResponseEntity<Void>, otherwise whatever is returned normally as generic type.
Came across this question and was surprised that no-one mentioned RedirectView. I have just tested it, and you can solve this in a clean 100% spring way with:
#RestController
public class FooController {
#RequestMapping("/foo")
public RedirectView handleFoo() {
return new RedirectView("some-url");
}
}
redirect means http code 302, which means Found in springMVC.
Here is an util method, which could be placed in some kind of BaseController:
protected ResponseEntity found(HttpServletResponse response, String url) throws IOException { // 302, found, redirect,
response.sendRedirect(url);
return null;
}
But sometimes might want to return http code 301 instead, which means moved permanently.
In that case, here is the util method:
protected ResponseEntity movedPermanently(HttpServletResponse response, String url) { // 301, moved permanently,
return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY).header(HttpHeaders.LOCATION, url).build();
}
As the redirections are usually needed in a not-straightforward path, I think throwing an exception and handling it later is my favourite solution.
Using a ControllerAdvice
#ControllerAdvice
public class RestResponseEntityExceptionHandler
extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = {
NotLoggedInException.class
})
protected ResponseEntity<Object> handleNotLoggedIn(
final NotLoggedInException ex, final WebRequest request
) {
final String bodyOfResponse = ex.getMessage();
final HttpHeaders headers = new HttpHeaders();
headers.add("Location", ex.getRedirectUri());
return handleExceptionInternal(
ex, bodyOfResponse,
headers, HttpStatus.FOUND, request
);
}
}
The exception class in my case:
#Getter
public class NotLoggedInException extends RuntimeException {
private static final long serialVersionUID = -4900004519786666447L;
String redirectUri;
public NotLoggedInException(final String message, final String uri) {
super(message);
redirectUri = uri;
}
}
And I trigger it like this:
if (null == remoteUser)
throw new NotLoggedInException("please log in", LOGIN_URL);
if you #RestController returns an String you can use something like this
return "redirect:/other/controller/";
and this kind of redirect is only for GET request, if you want to use other type of request use HttpServletResponse
I am using Jersey as the implementation library.
#Path("books")
public class Sample {
#GET
public List<Book> getBooks(#Context UriInfo uriInfo)
{
MultivaluedMap<String,String> params = uriInfo.getQueryParameters();
String pageStart = params.getFirst("p");
String pageSize = params.getFirst("s");
}
}
It works fine with /books but doesn't work for /books?p=1&s=10 (http 404 error)
I don't want to define my path like "books?p={p}&s={s}" since there will be dynamic parameters that cannot be predefined.
question:
Is there any way that i can map /books?p=1&s=10 to the getBooks method??
can check by having you #Path("books") changed to #Path("/books")
I'm successfully using Spring.net Rest on WP7 since this issue.
My REST service requires a specific content type. I tried to used another request interceptor but XElementHttpMessageConverter overrides the content type.
public MyClient(string baseAddress)
{
restTemplate = new RestTemplate(baseAddress);
//restTemplate.RequestInterceptors.Add(new NoCacheRequestInterceptor());
restTemplate.MessageConverters.Add(new XElementHttpMessageConverter());
}
public MyObject GetMyObject(int id)
{
XElement element = restTemplate.GetForObject<XElement>("path/{id}", id);
//..
return myObject;
}
// more methods
The best way here to do that is to configure your converter with the "SupportedMediaTypes" property :
public MyClient(string baseAddress)
{
restTemplate = new RestTemplate(baseAddress);
//restTemplate.RequestInterceptors.Add(new NoCacheRequestInterceptor());
XElementHttpMessageConverter linqXmlConverter = new XElementHttpMessageConverter ();
linqXmlConverter.SupportedMediaTypes = new MediaType[] { MediaType.Parse("type/subtype") };
restTemplate.MessageConverters.Add(linqXmlConverter );
}
Btw, you could do that with an interceptor too but not with the "IClientHttpRequestFactoryInterceptor" that intercepts request creation.
You should use instead "IClientHttpRequestBeforeInterceptor" that intercepts request execution.
I'm creating a small REST web service using Netbeans. This is my code:
private UriInfo context;
private String name;
public GenericResource() {
}
#GET
#Produces("text/html")
public String getHtml() {
//TODO return proper representation object
return "Hello "+ name;
}
#PUT
#Consumes("text/html")
public void putHtml(String name) {
this.name = name;
}
I'm calling the get method ok since when I call http://localhost:8080/RestWebApp/resources/greeting I get "Hello null" but I'm trying to pass a parameter using http://localhost:8080/RestWebApp/resources/greeting?name=Krt_Malta but the PUT method is not being called... Is this the correct way to pass a parameter or am I missing something?
I'm a newbie to Rest bdw, so sry if it's a simple question.
Thanks! :)
Krt_Malta
The second URL is a plain GET request. To pass data to a PUT request you have to pass it using a form. The URL is reserved for GET as far as I know.
If you build the HTTP-header yourself, you must use POST instead of GET:
GET /RestWebApp/resources/greeting?name=Krt_Malta HTTP/1.0
versus
POST /RestWebApp/resources/greeting?name=Krt_Malta HTTP/1.0
If you use a HTML-form, you must set the method-attribute to "PUT":
<form action="/RestWebApp/resources/greeting" method="PUT">
For JAX-RS to mactch a method annotated with #PUT, you need to submit a PUT request. Normal browsers don't do this but cURL or a HTTP client library can be used.
To map a query parameter to a method argument, JAX-RS provides the #QueryParam annotation.
public void putWithQueryParam(#QueryParam("name") String name) {
// do something
}
You can set:
#PUT
#path{/putHtm}
#Consumes("text/html")
public void putHtml(String name) {
this.name = name;
}
and if you use something like google`s Volley library you can do.
GsonRequest<String> asdf = new GsonRequest<String>(ConnectionProperties.happyhourURL + "/putHtm", String.class, yourString!!, true,
new Response.Listener<Chain>() {
#Override
public void onResponse(Chain response) {
}
}, new CustomErrorListener(this));
MyApplication.getInstance().addToRequestQueue(asdf);
and GsonRequest will look like:
public GsonRequest(String url, Class<T> _clazz, T object, boolean needLogin, Listener<T> successListener, Response.ErrorListener errorlistener) {
super(Method.PUT, url, errorlistener);
_headers = new HashMap<String, String>();
this._clazz = _clazz;
this.successListener = successListener;
this.needsLogin = needLogin;
_object = object;
setTimeout();
}