This is the class that I use to populate and send it as a part of my web service request call:
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class ClientInfo {
private String langCode;
private String userId;
private String password;
private String ShipTo;
private String timeZone;
public String getLangCode() {
return langCode;
}
public void setLangCode(String langCode) {
this.langCode = langCode;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getShipTo() {
return ShipTo;
}
public void setShipTo(String shipTo) {
ShipTo = shipTo;
}
public String getTimeZone() {
return timeZone;
}
public void setTimeZone(String timeZone) {
this.timeZone = timeZone;
}
}
When I am using Entity.xml() for this class to parse the class and initiate the request everything works fine, and I get the result back, this is part of the code for service invocation. Please look at the last line for Entity.xml();
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.client.ClientConfig;
ClientInfo ci = new ClientInfo();
ci.setLangCode("en");
ci.setPassword("password#123");
ci.setShipTo("0000");
ci.setTimeZone("420");
ci.setUserId("user1");
Invocation.Builder invocationBuilder = resourceWebTarget.request(MediaType.APPLICATION_XML);
Response response = invocationBuilder.post(Entity.xml(ci));
However, if I change the Entity.xml(ci) to Entity.json(ci), it will throw me an exception. The exception is as follow:
Apr 07, 2014 3:54:08 PM org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo
SEVERE: MessageBodyWriter not found for media type=application/json, type=class com.sheidaei.sample.appleclient.ClientInfo, genericType=class com.sheidaei.sample.appleclient.ClientInfo.
From what I read, my understanding is that the application can not find a JSON representation for the ClientInfo class. Is there an easy way (such as annotation) so that Entity.json() finds the JSON representation of the ClientInfo easily?
By default Jersey provides support for JAXB annotated classes and XML marshalling/unmarshalling. To use JSON you need an appropriate entity provider with the proper configurations.
The Jersey documentation provides the details: https://jersey.java.net/documentation/1.18/json.html
Related
I have this Model class:
package org.myapp.model;
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="Message")
#XmlAccessorType(XmlAccessType.FIELD)
public class Message {
public long id;
public String message;
public Date created;
public String author;
public Message() {
}
public Message(long id,String message, String author) {
this.id = id;
this.message = message;
this.author = author;
this.created = new Date();
}
#XmlElement
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#XmlElement
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
#XmlElement
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
The Service Class:
package org.myapp.services;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.myapp.model.Message;
public class MessageService {
public List<Message> getAllMessages(){
Message msg1 = new Message(1L,"How are you?", "natalie");
Message msg2 = new Message(2L,"How are you?", "amir");
List<Message> msglist = new ArrayList<Message>();
msglist.add(msg1);
msglist.add(msg2);
return msglist;
}
}
The Resource Class:
package org.myapp.resource;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.myapp.model.Message;
import org.myapp.services.MessageService;
#Path("messageresource")
public class MessageResource {
MessageService messageService = new MessageService();
#GET
#Produces(MediaType.APPLICATION_XML)
public List<Message> getMessage() {
return messageService.getAllMessages(); //"app chal rhi hai!";
}
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("/{messageId}")
public String getMessageID(#PathParam("messageId") String messageId) {
Message message = new Message(1L,"How are you?", "natalie");
return message.getMessage()+", "+messageId;
}
}
I am trying to print the data in Service(MessageService) class in an XML format. I think, the error is being caused because the return value of this class' method (return type List<Message>) and the tag #XMLRootElement on the top of the Model (Message) class are not consistent. I tried different MediaType properties but nothing helped.
When I am accessing this path : localhost:8080/messengerapp/webapi/messageresource
I am getting this error - Internal Server Error
I have just started to learn to write web services.I have tried different ways to get around this problem but nothing is helping me. Please help me understand and solve this.
try with this,
annotate the root element of xml
#XmlRootElement (name="Messages")
public class MessageService implements Serializable{
private List<Message> msglist = new ArrayList<Message>();
public List<Message> getAllMessages(){
Message msg1 = new Message(1L,"How are you?", "natalie");
Message msg2 = new Message(2L,"How are you?", "amir");
msglist.add(msg1);
msglist.add(msg2);
return msglist;
}
public void setAllMessages(List<Message> msglist){
this.msglist = msglist;
}
}
structure of the xml
<Messages> <!-- root element of xml -->
<Message>
...
</Message>
<Message>
...
</Message>
</Messages>
I have a rest API (PUT verb) which accepts both request body and path params:
Ex:
curl --data {a:1, b:2} -X PUT "https://example.com/users/{username}/address/{addressname}"
I am trying to fetch both request body and path param in one POJO
Response myAPI(#BeanParam Users user){
system.out.println(user.username);
system.out.println(user.a);
Users class
public class Users{
#PathParam(username)
private String userName;
......
private String a;
......
}
But I am getting value of user.a as null.
How to parse both request body and param in same class?
You can do this with a custom annotation and an InjectionResolver. What the InjectionResolver does is allow you to create a custom injection point with your own annotation. So you could do something like
public class Users {
#PathParam(username)
private String userName;
#Body
private String a;
}
When implementing the InjectionResolver, you would grab the actual body from the ContainerRequest using the ContainerRequest#readEntity(Class) method. You would determine the Class to pass by doing some reflection on the Field that you can obtain inside the InjectionResolver. Below is a complete example using Jersey Test Framework. Run it like any other JUnit test.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.BeanParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
/**
* Only one required dependency to run this test. Note this is using 2.25.1.
* If you are using 2.26 or later, the implementation will be different,
* and this will not work. You need to use the Jersey packaged `InjectionResolver`,
* not the HK2 one. And you will also need to bind that `InjectionResolver`
* to `GenericType` instead of `TypeLiteral` in the `AbstractBinder#configure()`.
*
* <dependency>
* <groupId>org.glassfish.jersey.test-framework.providers</groupId>
* <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
* <version>2.25.1</version>
* <scope>test</scope>
* </dependency>
*/
public class BeanParamTest extends JerseyTest {
#Path("test")
#Consumes("application/json")
#Produces("application/json")
public static class TestResource {
#POST
#Path("{username}")
public String post(#BeanParam ModelBean bean) {
return bean.toString();
}
}
#Override
public ResourceConfig configure() {
return new ResourceConfig(TestResource.class)
.register(new AbstractBinder() {
#Override
protected void configure() {
bind(BodyInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<Body>>() {})
.in(Singleton.class);
}
});
}
#Test
public void testIt() {
final Response res = target("test/peeskillet")
.request()
.post(Entity.json("{\"foo\":\"bar\"}"));
System.out.println(res.readEntity(String.class));
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD})
public #interface Body {}
public static class ModelBean {
#PathParam("username")
private String username;
#Body
private String body;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
#Override
public String toString() {
return "ModelBean{" +
"username='" + username + '\'' +
", body='" + body + '\'' +
'}';
}
}
public static class BodyInjectionResolver implements InjectionResolver<Body> {
#Inject
private javax.inject.Provider<ContainerRequest> requestProvider;
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> serviceHandle) {
if (injectee.getParent().isAnnotationPresent(Body.class)) {
AnnotatedElement parent = injectee.getParent();
if (parent instanceof Field) {
Class<?> entityType = ((Field) parent).getType();
return requestProvider.get().readEntity(entityType);
}
}
return null;
}
#Override
public boolean isConstructorParameterIndicator() {
return false;
}
#Override
public boolean isMethodParameterIndicator() {
return false;
}
}
}
I'm a beginner trying to learn about RESTful API in Java. I have created a Dynamic Web project in Eclipse and tried to receive JSON data in request.
#Path("/test")
public class TestAPI {
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String sayHello(User user) {
String name = user.getName();
return name;
}
}
#XmlRootElement(name = "user")
#XmlAccessorType(XmlAccessType.FIELD)
class User{
private String name;
public User() {}
#XmlElement
public void setName(String s) {
this.name = s;
}
public String getName() {
return name;
}
public String toString(){
return "{\"name\": "+name+"}";
}
}
In this code, I have tried to create a class User which only have one attribute name. I'm trying to send the name as JSON in request and retrieve the name from JSON.
HTTP Status 500 - javax.ws.rs.ProcessingException: Error deserializing
object from entity stream
error.
Can anyone tell me what's wrong with my code?
Thanks in advance.
Edit: Import section is
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
Try removing all the xml tags from your POJO and run.
Like this:
class User{
private String name;
public void setName(String s) {
this.name = s;
}
public String getName() {
return name;
}
public String toString(){
return "{\"name\": "+name+"}";
}
}
Request JSON:
{"name" : "Your Name"}
Hope it helps.
I have developed one restful webservice using jersey and spring.
Below is the service method which servers the request by accepting the list of Login objects.
Method in service class
#POST
#Path(value = "/login")
#Produces(MediaType.APPLICATION_XML)
public String getLogin(Login login);
#POST
#Path(value = "/update")
#Consumes(MediaType.APPLICATION_XML)
public void updatePassword(List<Login> userList)
Login class
#XmlRootElement
public class Login {
//some code
}
I am using the jersey client to consume this webservice as below.
loginList = ArrayList of Login objects
Client client = Client.create();
WebResource webResource = client.resource("http://localhost:8080/user/update");
ClientResponse response = webResource.accept(MediaType.APPLICATION_XML).type(MediaType.APPLICATION_XML).post(ClientResponse.class, loginList);
But below is the exception which I am getting.
Caused by: com.sun.jersey.api.client.ClientHandlerException: A message body writer for Java type, class java.util.ArrayList, and MIME media type, application/xml, was not found
at com.sun.jersey.api.client.RequestWriter.writeRequestEntity(RequestWriter.java:288)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:204)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:147)
But My /login i.e. getLogin method works perfectly.
I am not able to figure out what exactly is causing this issue.
Can anyone please help me what could be the wrong happening in this.
Thanks in advance.
I guess you need to use GenericEntity for generic types, because of type erasure. And JAXB needs to know the type. The GenericEntity stores the type through it parameter. So basically, you just need to do
.post(ClientResponse.class, new GenericEntity<List<Login>>(list){});
UPDATE
complete test using Jersey Test Framework
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-grizzly2</artifactId>
<version>1.19</version>
<scope>test</scope>
</dependency>
Login
#XmlRootElement
public class Login {
private String name;
private String password;
public Login() {
}
public Login(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Override
public String toString() {
return "Login{" + "name=" + name + ", password=" + password + '}';
}
}
Test
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.core.DefaultResourceConfig;
import com.sun.jersey.spi.container.servlet.WebComponent;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.WebAppDescriptor;
import com.sun.jersey.test.framework.spi.container.TestContainerFactory;
import com.sun.jersey.test.framework.spi.container.grizzly2.web.GrizzlyWebTestContainerFactory;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import org.junit.Test;
public class ArrayTest extends JerseyTest {
#Path("/login")
public static class LoginResource {
#POST
#Consumes(MediaType.APPLICATION_XML)
public String post(List<Login> logins) {
return new HashSet<>(logins).toString();
}
}
public static class AppConfig extends DefaultResourceConfig {
public AppConfig() {
super(LoginResource.class);
}
}
#Override
public TestContainerFactory getTestContainerFactory() {
return new GrizzlyWebTestContainerFactory();
}
#Override
public WebAppDescriptor configure() {
return new WebAppDescriptor.Builder()
.initParam(WebComponent.RESOURCE_CONFIG_CLASS,
AppConfig.class.getName())
.build();
}
#Test
public void doTest() {
List<Login> list = new ArrayList<>();
list.add(new Login("pee", "skillet"));
ClientResponse response = resource().path("login")
.type(MediaType.APPLICATION_XML)
.post(ClientResponse.class, new GenericEntity<List<Login>>(list){});
System.out.println("Status " + response.getStatus());
System.out.println(response.getEntity(String.class));
}
}
If you remove the GenericEntity, you will get the error.
I am using the Jersey Client of Sun Version 1.19...
When I send a put request with JSON (but every other request type probably as well) it serializes Number-typed variables with quotes, instead of as plain numbers.
Example:
User.java
package de.topazmedia.component.api.rest.client.ressource;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
public class User {
Long id;
String username;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return id;
}
public void setUsername(Long id) {
this.id = id;
}
}
Test.java
import javax.ws.rs.core.MediaType;
import org.json.JSONObject;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.WebResource.Builder;
public class Test {
public static void main(String[] args) {
User user = new User();
user.setId(1);
user.setUsername("Test");
ClientResponse response = null;
WebResource webResource = client.resource(http://192.168.23.56:9181/v1/users/" + user.getId());
Builder builder = webResource.header("Accept-Language", "de").type(MediaType.APPLICATION_JSON_TYPE).accept(MediaType.APPLICATION_JSON_TYPE);
response = builder.put(ClientResponse.class, user);
}
}
The "User JSON" I put as entity in the request is now translated to
{"id":"1","username":"Test"}
BUT it should be without the apostrphes at the id like this:
{"id":1,"username":"Test"}
What is wrong?
The solution of the problem ist quite simple.
Just define a POJO-Mapping in the ClientConfig when instantiating the Client Object:
ClientConfig cc = new DefaultClientConfig();
cc.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
client = Client.create(cc);