I am trying to implement a RESTful Web Service with Jackson and Jersey Servlets. My Webservices can produce this particular JSON as shown
{
"email":"aditya#123.com",
"source":{
"G":33.2470567,
"K":-95.89996559999997
},
"destination":{
"G":33.0198431,
"K":-96.69888559999998
},
"waypoints":[
{
"location":"Dallas, TX, USA",
"stopover":true
},
{
"location":"Houston, TX, USA",
"stopover":true
}
]
}
But when I try to consume the Same JSON it gives an internal server 500 error:
org.codehaus.jackson.JsonParseException: Unexpected character ('Â' (code 194)): was expecting double-quote to start field name
My POJOs & web service is as shown:
#XmlRootElement
public class RiderVO {
private String email;
private MapLocation source;
private MapLocation destination;
private List<Waypoint> waypoints;
//getters and setters
}
#XmlRootElement
public class MapLocation {
private Double G;
private Double K;
//getters and setters
}
#XmlRootElement
public class Waypoint {
private String location;
private Boolean stopover;
//getters & setters
}
WEB SERVICE:
#POST
#Path("/saveAll")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String saveRideJson(RiderVO riderVO){
//do something
}
I cannot figure out when it can produce a particular JSON why cannot I consume it. I did try changing the boolean parameters, and check if its isVar setter issues like here. But even that did not fix. Any suggestions are helpful. Thanks in advance!
Related
I am working on an embedded jersey instance which will run a JAXB RESTful service. I have configured Jackson with two steps:
Adding this to my POM
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.23.2</version>
</dependency>
Registering it in my application
public HandheldApplication() {
scripts.add(HandheldServer.class);
scripts.add(BasicScript.class);
// Add JacksonFeature.
scripts.add(JacksonFeature.class);
scripts.add(LoggingFilter.class);
}
I have a complex object being passed back and forth as shown below:
package com.ziath.handheldserver.valueobjects;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.*;
#SuppressWarnings("restriction")
#XmlRootElement
public class Widget {
private String key;
private String name;
private List<String> options = new ArrayList<String>();
private String value;
private String type;
public Widget(){
super();
}
public Widget(String key, String name, List<String> options, String value,
String type) {
super();
this.key = key;
this.name = name;
this.options = options;
this.value = value;
this.type = type;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getOptions() {
return options;
}
public void setOptions(List<String> options) {
this.options = options;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
When I execute this in a GET method as shown below:
#Override
#GET
#Path("getKeys")
#Produces(MediaType.APPLICATION_JSON)
public List<Widget> getKeys(#QueryParam(value = "page") int page)
This works fine and I get JSON back; however when I execute it is a PUT as shown below:
#Override
#PUT
#Path("validateKeys")
#Produces({MediaType.APPLICATION_JSON})
#Consumes(MediaType.APPLICATION_JSON)
public boolean validateKeys(#QueryParam(value = "page")int page, #QueryParam(value = "widgets")List<Widget> widgets)
When I execute a PUT to access this method I get a stack trace as follows:
Caused by: org.glassfish.jersey.internal.inject.ExtractorException: Error un-marshalling JAXB object of type: class com.ziath.handheldserver.valueobjects.Widget.
at org.glassfish.jersey.jaxb.internal.JaxbStringReaderProvider$RootElementProvider$1.fromString(JaxbStringReaderProvider.java:195)
at org.glassfish.jersey.server.internal.inject.AbstractParamValueExtractor.convert(AbstractParamValueExtractor.java:139)
at org.glassfish.jersey.server.internal.inject.AbstractParamValueExtractor.fromString(AbstractParamValueExtractor.java:130)
at org.glassfish.jersey.server.internal.inject.CollectionExtractor.extract(CollectionExtractor.java:88)
at org.glassfish.jersey.server.internal.inject.CollectionExtractor$ListValueOf.extract(CollectionExtractor.java:107)
at org.glassfish.jersey.server.internal.inject.QueryParamValueFactoryProvider$QueryParamValueFactory.provide(QueryParamValueFactoryProvider.java:89)
... 38 more
Caused by: javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.]
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:563)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:249)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:140)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:123)
at org.glassfish.jersey.jaxb.internal.JaxbStringReaderProvider$RootElementProvider$1.fromString(JaxbStringReaderProvider.java:190)
... 43 more
So it seems to me that Jackson is correctly marshalling my POJO into JSON but trying to unmarshall it as XML. Note that I switched to Jackson away from MOXy because I needed to be able to handle collections coming back and forth and apparently MOXy cannot do that.
Is there a setting I've missed to tell Jackson/Jersey to go both ways for JSON?
Try removing #QueryParam(value = "widgets") because you should pass it as entity body - not query param.
#PUT
#Path("validateKeys")
#Produces({MediaType.APPLICATION_JSON})
#Consumes(MediaType.APPLICATION_JSON)
public boolean validateKeys(#QueryParam(value = "page")int page, List<Widget> widgets)
Also you can make wrapper class:
#XmlRootElement
public class Widgets {
private List<Widget> widgets;
// other fields, setters and getters
}
And then:
#PUT
#Path("validateKeys")
#Produces({MediaType.APPLICATION_JSON})
#Consumes(MediaType.APPLICATION_JSON)
public boolean validateKeys(#QueryParam(value = "page")int page, Widgets widgets)
I would suggest to read some discussions about REST design because you're using verbs in your paths:
Is this a bad REST URL?
Understanding REST: Verbs, error codes, and authentication
I was switching between QueryParam and FormParam to try and get one of them to work. If I use FormParam I also need to change the consumes to APPLICATION_FORM_URLENCODED.
The actual issue was that the default unmarshalling with Jackson was using XML because it was tagged as an XML resource - take that out! I finally managed to work out how to unmarshall from JSON by using a static fromString method. Then to handle the list; I cannot use a wrapper class because this needs to be highly cross language and exposing a wrapper with a list would have complicated the implementation from Python, C#, etc. The way to get it to accept a list with a wrapper is to post the name of the param (in this case widgets) multiple time. Then each JSON passed in will be called against the fromString method.
I implemented Rest api with Spring Boot. In my controller class, I have code to handle GET request which will return JSON if record found.
// SeqController.java
#Autowired
private SeqService seqService;
#RequestMapping(
value = "/api/seqs/{analysis_id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<SeqTb>> getSeqByAnalysisId(#PathVariable("analysis_id") String analysis_id) {
List<SeqTb> seqs = seqService.findByAnalysisId(analysis_id);
return new ResponseEntity(seqs, HttpStatus.OK);
}
I also create a bean class SeqServiceBean that extends the interface SeqService which in turn calls methods from the following JPA repository for query.
//SeqRepository.java
#Repository
public interface SeqRepository extends JpaRepository<SeqTb, Integer> {
#Override
public List<SeqTb> findAll();
public List<SeqTb> findByAnalysisId(String analysisId);
}
Problem is when I typed the url (http://localhost:8080/api/seqs/fdebfd6e-d046-4192-8b97-ac9f65dc2009) in my browser, it returned nothing but a pair of empty brackets. I just looked in the database and that record is indeed there. What did I do wrong?
A bit late to answer this quesiton, but in case anyone else is having this issue.
This problem may be caused by the class (that we want to be displayed as a json object) missing getter and/or setter methods.
In your case the "seqTab" class may be not have getters.
Without the getters our application can not extract the fileds to build the json object.
Example :
Sample user class
public class User {
private String firstname;
private String lasttname;
int age;
public User(){
}
public User(String fname, String lname, int age){
this.firstname = fname;
this.lasttname = lname;
this.age = age;
}
}
Sample rest controller
#RestController
public class SampleRS {
#RequestMapping(value = {"/sample/{input}"}, method = RequestMethod.GET , produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> startService(#PathVariable("input") String input){
User u = new User(input,"bikila",45);
return new ResponseEntity<User>(u,HttpStatus.OK);
}
}
// If we try to hit the endpoint /sample{input} .. e.g.
Request : localhost:8080/Sample/abebe
Response :
{}
But adding the getters for the User class will solve the problem.
Modified User class with getters
public class User {
private String firstname;
private String lasttname;
int age;
public User(){
}
public User(String fname, String lname, int age){
this.firstname = fname;
this.lasttname = lname;
this.age = age;
}
public String getFirstname() {
return firstname;
}
public String getLasttname() {
return lasttname;
}
public int getAge() {
return age;
}
}
Request : http://localhost:8080/sample/abebe
Response : {"firstname":"abebe","lasttname":"bikila","age":45}
Hope that helps !
In most of case, database driver jar is not deployed in server. Check deployment assembly of project in eclipse. Also see console message to check if it is showing driver jar not found.
If this is case simply deploy this jar in deployment assembly of eclipse.
One thing, if build path has this jdbc driverjar in eclipse, main method will connect to database. But if jar is not deployed jdbc connection will not happen over http request.
I am attempting to write a simple test class that emulates a RESTful Web Service creating a Customer via a POST method. The following fails at assertEquals, I receive a 400 Bad Request response. I cannot use debugger to observe stack trace. However the console tells me the following...
INFO: Started listener bound to [localhost:9998]
INFO: [HttpServer] Started.
public class SimpleTest extends JerseyTestNg.ContainerPerMethodTest {
public class Customer {
public Customer() {}
public Customer(String name, int id) {
this.name = name;
this.id = id;
}
#JsonProperty("name")
private String name;
#JsonProperty("id")
private int id;
}
#Override
protected Application configure() {
return new ResourceConfig(MyService.class);
}
#Path("hello")
public static class MyService {
#POST
#Consumes(MediaType.APPLICATION_JSON)
public final Response createCustomer(Customer customer) {
System.out.println("Customer data: " + customer.toString());
return Response.ok("customer created").build();
}
}
#Test
private void test() {
String json = "{" +
"\"name\": \"bill\", " +
"\"id\": 4" +
"}";
final Response response = target("hello").request(MediaType.APPLICATION_JSON_TYPE).post(Entity.json(json));
System.out.println(response.toString());
assertEquals(response.getStatus(), 200);
}
}
Instead of printing response.toString(), you can read the actual body using response.readEntity(String.class). What you will find in the body is an error message from Jackson
No suitable constructor found for type [simple type, class simple.SimpleTest$Customer]: can not instantiate from JSON object (need to add/enable type information?)
At first glance your Customer class looks ok; it has a default constructor. But the really problem is that Jackson cannot instantiate it because it is a non-static inner class. So to fix it, simply make the Customer class static.
public static class Customer {}
As a general rule, when working with JSON and Jackson with Jersey, often when you get a 400, it a a problem with Jackson, and Jackson is pretty good at spitting out a meaningful message that will help us debug.
I'm working on a jax-rs RESTful application and I have a service that is supposed to save a JSON objet into a database through JPA. The service class is something like:
#Path("/items")
#Stateless
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class ItemsService {
#Inject
protected IItemsLogic itemsServiceLogic;
#POST
public ItemDTO create(ItemDTO item){
return itemsServiceLogic.createItem(item);
}
}
the itemsServiceLogic is just a class that transforms the DTO into another Java class declared as an entity in order to be serialized in a database through JPA.
What happens is that I'm testing the application through the google chrome browser client Postman but when I send a JSON objet into the POST method, the received DTO has no properties so the database doesn't save anything, as all the DTO's properties are null.
I'm using Glassfish 4.0 to host my application and everything with the database works fine. What could be wrong?
The DTO class would be:
#XmlRootElement
public class ItemDTO {
//Id private
Long id;
//item's description
private String description;
//item's name
private String name;
//Setters and getters
public Long getId(){
return id;
}
public String getDescription(){
return description;
}
public String getName(){
return name;
}
public void setId(Long nId){
this.id=nId;
}
public void setDescription(String nDescription){
this.description = nDescription;
}
public void setName(String nName){
this.name=nName;
}
}
And i'm sending the JSON:
{"id":1,"description":"some item","name":"item1"}
I am using jersey in Java. I want to get JSON data sent via a post request. However, I am not sure how to do this, despite my searching. I am able to receive JSON data at a path, yet I can't figure out how to parse it into java variables. I assume that I need to use jackson to do this. However, I don't understand how to pass the received JSON to jackson.
#Path("/register")
public class ResourceRegister
{
#POST
#Consumes(MediaType.APPLICATION_JSON)
public String RegisterUser(//not sure what to take in here to get the json )
{
//code to deal with the json
}
There are several ways of accepting the JSON and using it in back-end.
1. set POJO elements using JAXB APIs and use object of that POJO class to access passed parameters. this will be helpful while JSON size is large.
Example:
your service declaration would be as following
#Path("/register")
public class ResourceRegister
{
#POST
#Consumes(MediaType.APPLICATION_JSON)
public String RegisterUser(RegParams regParams)
{
//code to deal with the json
}
.....
}
and you will write a POJO like following
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#JsonIgnoreProperties(ignoreUnknown=true)
#JsonWriteNullProperties(false)
public class RegParams implements Serializable {
#JsonProperty("userId")
private long userId;
#JsonProperty("userName")
private String userName;
..
..
}
retrive JSON as a string and use jersey APIs to work with the same.
in this case you can declare your service as following
#Path("/register")
public class ResourceRegister
{
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String RegisterUser(#FormParam("jsonObj")String jsonString)
{
//code to deal with the json
}
.....
}
and you can process that string by using jersey APIs like following
ObjectMapper om = new ObjectMapper();
JsonNode mainNode = om.readTree(jsonString);
//access fields
mainNode.get..(as per data passed, string, int etc)
for more referance you can refer this or this
You just need to place #JsonProperty annotation to your class properties and add that class to your Resource method as paramater.
You might need #JsonIgnoreProperties annotation as well if you are not deserializing everything inside the incoming json
See below:
#POST
#Consumes(MediaType.APPLICATION_JSON)
public String registerUser(MyUser myUser)
{
//code to deal with the json
}
public class MyUser{
#JsonProperty
private String name;
#JsonProperty
private String surname;
//getters & setters & constructors if you need
}