Why wrong path annotation doesn't crash REST API with Jersey? - java

I have a running RESTful API fully working with everything ok. I'm using a HTML with JS to access my REST methods with Jersey and Tomcat7 to host it. This is the code:
package pact;
import java.io.IOException;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.google.gson.Gson;
import repo.Pessoa;
import repo.Repo;
#Path("/")
public class Rest {
Gson gson = new Gson();
#POST
#Path("escreve")
#Consumes(MediaType.APPLICATION_JSON)
public void escreve(String dado) throws IOException {
Pessoa pessoa = gson.fromJson(dado, Pessoa.class);
Repo.escreve(pessoa);
}
#GET
#Path("le")
#Produces(MediaType.APPLICATION_JSON)
public String le() {
List<Pessoa> list = Repo.le();
String json = gson.toJson(list);
return json;
}
#POST
#Path("loja")
#Consumes(MediaType.APPLICATION_JSON)
public void loja(String dado){
Repo.seleciona(gson.fromJson(dado, Pessoa.class));
}
#GET
#Path("lojale")
#Produces(MediaType.APPLICATION_JSON)
public String lojale() {
return gson.toJson(Repo.retorna());
}
}
The problem is, if I change my web.xml at <url-pattern>/rest/*</url-pattern> to something like <url-pattern>/reste/*</url-pattern> Tomcat's description automatically changes to "Restart" and after restarting, all routes are changed to access my REST methods. Why I change #Path("/") to something like #Path("/pessoa/*") nothing happens, even saving all project, deleting Tomcat, creating another Server and publishing on it. Does this line matters? I've saw it in a tutorial and never changed. Does Jersey uses something like this?

Have you tried to set #Path("/pessoa/") instead of #Path("/pessoa/*") . I think you do not need the * as only /pessoa/ itself will match both /pessoa and /pessoa/something

Related

spring boot upload file with the other parameter by using #RequestPart cause Excption

when using spring boot upload file with parameter, I used #RequestPart for all parameter.
Here the code:
spring boot: 2.7.8
when one of them is String and the other is Integer and both of them annotated by #RequestPart will be cause Exception
package com.interfaces.anti.mage.api;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.interfaces.anti.mage.model.Address;
import com.interfaces.anti.mage.model.Order;
import com.interfaces.anti.mage.service.OrderService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
/**
* #author dengbojing
*/
#RestController
#RequestMapping("/order")
public class OrderApi {
#PostMapping("/upload")
public String upload(#RequestPart("file")MultipartFile file, #RequestPart("id") String id, #RequestPart("number") Integer number) {
System.out.println(id);
System.out.println(number);
return "success";
}
}
Exception info:
2023-02-13 22:51:40,319 WARN [http-nio-8099-exec-2] org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver: Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported]
when all the other parameter type is String and annotated by #RequestPart, the method will be worked and print the info.
#PostMapping("/upload")
public String upload(#RequestPart("file")MultipartFile file, #RequestPart("id") String id, #RequestPart("number") String number) {
System.out.println(id);
System.out.println(number);
return "success";
}
So why this? the exception means the program treat the String and Integer paramter as Stream? but why all String will be fine?
ps: even change to this #PostMapping(value = "/upload", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE}) also got the same problem
ps: this is the request info:
I take the chance of this post because it pointed me to the right direction anyway so, for sake of anyone using Postman, receiving the error above here is my hint, learnt with pain and solved thanks to the hints above.
In Postman, when you fill a form-data body, the table misses, by default I believe, the CONTENT TYPE column.
You can add the column the using the button on the right side, but then it will show Auto consequently, depending from your parameters, you should change it to the proper type.
I hope it may help others :)
Regards

How can I receive dynamically number of query params in Rest Client - Quarkus?

I need create a rest client to access a URI that can receive 0 or n query params.
Example:
https://xpto?page=0&size=10&brand=abc&color=blue or
https://xpto?page=0&size=10&brand=abc or
https://xpto?page=0&size=10 or
https://xpto
how could i do this here?
#RegisterRestClient
public interface BarService {
#GET
#Path("/xpto")
Response get(#QueryParam ...);
}
Please refer to How to send a query params map using RESTEasy proxy client, similar issue is being discussed.
You can define your client similar to below:
#RegisterRestClient
public interface BarService {
#GET
#Path("/xpto")
Response get(Map<String, String> queryParamMap);
}
And you can define ClientRequestFilter for converting the Map to Query Parameters:
import java.io.IOException;
import java.util.Map;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.ext.Provider;
#Provider
public class QueryParamBuildingFilter implements ClientRequestFilter {
#Override
public void filter(ClientRequestContext requestContext) throws IOException {
if (requestContext.getEntity() instanceof Map && requestContext.getMethod().equals(HttpMethod.GET)) {
UriBuilder uriBuilder = UriBuilder.fromUri(requestContext.getUri());
Map allParam = (Map)requestContext.getEntity();
for (Object key : allParam.keySet()) {
uriBuilder.queryParam(key.toString(), allParam.get(key));
}
requestContext.setUri(uriBuilder.build());
requestContext.setEntity(null);
}
}
}

Usage of client.reset in CXF Rest client

I am working on Rest web services and client using CXF 3.1.2 , and i have few clarification as below,
Service:
import javax.jws.WebService;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
public class GenServiceImpl {
#GET
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.TEXT_PLAIN)
#Path("/agentLogin/{ext}")
public String agentLogin(#PathParam("ext") Integer ext) {
return "EventAgentLoggedIn";
}
#POST
#Produces(MediaType.TEXT_PLAIN)
#Consumes({"application/xml", MediaType.TEXT_PLAIN})
#Path("/agentLogout")
public String agentLogout(String ext) {
return "EventAgentLoggedOut";
}
}
Client:
import javax.ws.rs.core.Response;
import org.apache.cxf.jaxrs.client.WebClient;
public class TestClient {
static final String REST_URI = "http://localhost:8080/RestfulSample/Restful";
public static void main(String[] args) {
WebClient client = WebClient.create(REST_URI);
//Get
client.path("agentLogin").path(new Integer(1234)).accept(MediaType.TEXT_PLAIN);
String agentLoginResponse = client.get(String.class);
System.out.println(agentLoginResponse);
client.reset();
//Post
client.path("agentLogout").accept(MediaType.TEXT_PLAIN);
Response agentLogoutResponse = client.post("10245");
System.out.println(agentLogoutResponse.readEntity(String.class));
client.reset();
}
Clarifications:
In my above example - In service class Post method(agentLogout) , i am getting error if i replace #Consumes({"application/xml", MediaType.TEXT_PLAIN})
with
#Consumes(MediaType.TEXT_PLAIN) whereas it works fine in Get method(agentLogin), may i know why it is so?
It is right to use client.reset(); - Here i am trying to use single WebClient to access all my methods.
Could you please let me know what i tried in my example is best practice ? and it will be appreciated if you could correct me here
Thanks,
Here are the clarifications.
Set content type to text/plain while posting. And you can set in your servers side class #Consumes(MediaType.TEXT_PLAIN)
client.replaceHeader("Content-Type",MediaType.TEXT_PLAIN);
Yes you can use rest method, here is java doc
When reusing the same WebClient instance for multiple invocations,
one may want to reset its state with the help of the reset() method,
for example, when the Accept header value needs to be changed and the
current URI needs to be reset to the baseURI (as an alternative to a
back(true) call). The resetQuery() method may be used to reset the
query values only. Both options are available for proxies too.
I would prefer to use proxy and access REST more like OOPS.
You could create interface for the above server class(Generally I careate REST definition as interface and then implement the interface( more like SOAP way)), which could be auto generated using WADLToJava maven plugin from WADL.
Here is sample interface for above server side rest class
public interface GenService {
#GET
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.TEXT_PLAIN)
#Path("/agentLogin/{ext}")
public String agentLogin(#PathParam("ext") Integer ext);
#POST
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.TEXT_PLAIN)
#Path("/agentLogout")
public String agentLogout(String ext);
}
Since you are not using spring , I will create a singleton class
public class CxfRestSingleton {
public static GenService obj;
public static GenService getInstance() {
if (obj == null) {
obj = JAXRSClientFactory.create("http://localhost:8080/RestfulSample/Restful", GenService.class);
}
return obj;
}
}
And you can access the rest using below code.
public static void main( String[] args )
{
System.out.println( CxfRestSingleton.getInstance().agentLogin(12345));
}

Invoke RESTful webservice with parameter

I have a simple RESTful web service that print "Hello World !"
I'm using NetBeans and the code looks like:
package resource;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Consumes;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
#Path("simple")
public class SimpleResource {
#Context
private UriInfo context;
/** Creates a new instance of SimpleResource */
public SimpleResource() {
}
#GET
#Produces("application/xml")
public String getXml() {
//TODO return proper representation object
return "<greeting>Hello World !</greeting>";
}
#PUT
#Consumes("application/xml")
public void putXml(String content) {
}
}
I call this web service from this URL : http://localhost:8080/WebService/resources/simple.
Now, I want to send a parameter to this web service, then print this parameter after the "Hello world" message.
How can we do that?
Thanks!
The two main ways of handling a parameter in REST are via parsing the path and via extracting the query part.
Path parameters
These handle this case — /foo/{fooID} — where {fooID} is a template that will be replaced by the parameter you want:
#GET
#Produces("text/plain")
#Path("/foo/{fooID}")
public String getFoo(#PathParam("fooID") String id) {
// ...
}
These are great for the case where you can consider the parameter to be describing a resource.
Query parameters
These handle this case — /?foo=ID — just like you'd get from doing traditional form processing:
#GET
#Produces("text/plain")
#Path("/")
public String getFoo(#QueryParam("foo") String id) {
// ...
}
These are great for the case where you consider the parameter to be describing an adjunct to the resource, and not the resource itself. The #FormParam annotation is extremely similar, except it is for handling a POSTed form instead of GET-style parameters
Other types of parameters
There are other types of parameter handling supported by the JAX-RS spec (matrix parameters, header parameters, cookie parameters) which all work in about the same way to the programmer, but are rarer or more specialized in use. A reasonable place to start exploring the details is the JAX-RS javadoc itself, as that has useful links.
The sample code for a web service which accepts parameters in URl will look like this:
#GET
#Path("/search")
public String getUserDetailsFromAddress(
#QueryParam("name") String name) {
return "Hello"+name;
}
and the URL will be like this:
http://localhost:8080/searchapp/mysearch/search?name=Tom
Try adding a Path annotation like this:
#javax.ws.rs.Path(“/bookstore/books/{bookId}”)

Why writer for media type application/json missing

Basically I have a restful service (post) that consumes(application/json) and produces (application/json). The single param for this service is an annotated java object.
I am using org.jboss.resteasy.client.ClientRequest to send the request to the service. However, I am getting this exception in the client end and the exception:
could not find writer for content-type application/json type.
Does this mean that I am missing some library jars or I have to write my own writer for application/json?
I am using resteasy 1.1
Mark
Raman is correct. Jettison is a valid option. You can also use Jackson.
If you are using maven, it is as simple as including the following dependency in you pom:
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>2.3.2.Final</version>
</dependency>
At which point you should have no problem writing code such as:
SomeBean query = new SomeBean("args")
request.body("application/json", query);
ClientResponse response = request.post();
actually I had the same problem, I did solve it by adding jettison provider for application/json mime type. I don't know whether resteasy 1.1 containts jettison provider but version 1.2 does.
Also if you are using jdk 1.6 you must exclude javax.xml.stream:stax-api jar file, otherwise you will have a problem.
Here is the example:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="account")
public class Account {
private Long id;
private String accountNo;
public Account(){}
public Account(String no) {
accountNo=no;
}
#Id
#XmlElement
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#XmlElement
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String a) {
accountNo = a;
}
}
and JAXB class:
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
#Path("/account")
public class AccountService {
#GET
#Path("/{accountNo}")
#Produces("application/json")
public Account getAccount(#PathParam("accountNo") String accountNo) {
return new Account(accountNo);
}
}
That's all, have a nice day!
Add below to the Resource class or the method causing the exception
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)

Categories