sending arraylist from a rest service - json

I am new to webservices and also REST. I am trying to send a message as a post request to a rest service using rest java client.I am trying to get response of previous requests also(everything in json format). So, am storing the message objects into an arraylist and sending the list as a reponse. But I am not able to get the previous messages. Please tell me if am doing anything wrong.
This is my message model class.
public class Messages {
private String id;
private String message;
public Messages() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
the following is my webservice to receive a message object and return a json array.
#Path("/json/messages")
public class JSONMessages {
public List<Messages> list = new ArrayList<Messages>();
List<Messages> getAllMessages(Messages m){
list.add(m);
return list;
}
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response MessageListInJSON(Messages msg) {
System.out.println("message saved");
if(!(msg.getId().equals("1"))){
String output ="Invalid User";
return Response.ok(output).build();
}
else{
return Response.ok(getAllMessages(msg)).build();
}
}
}
Finally, the following is my client side code
public class ClientPost {
public static void main(String[] args) {
try {
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
WebResource webResource = client
.resource("http://localhost:8050/lab.rest.webservices/rest/json/messages/post");
//for(int i=0;i<5;i++){
String input = "{\"id\":\"1\", \"message\":\"hey there!\"}";
ClientResponse response = webResource.accept("application/json").type("application/json")
.entity(input).post(ClientResponse.class);
if (response.getStatus() !=200 ) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
System.out.println(output+"\n");
}
catch (Exception e) {
e.printStackTrace();
}
} }
Now, what I am expecting to see is the message I sent along with the previous responses stored in the array list(which were sent by running the client multiple times manually for now) but always am ending up with only the current message.
output:
Output from Server ....
[{"id":"1","message":"hey there!"}]
To be precise, what I want as output when i run my client several times(or put the try block in loop) is as follows which i am unable to get.
Output from Server ....
[{"id":"1","message":"hey there!"},{"id":"1","message":"hey there!"},{"id":"1","message":"hey there!"},{"id":"1","message":"hey there!"}] .

Resources in JAXRS aren't singletons. That means that for each request, the class JSONMessages is instantiated. So you lose the content of the attribute list. Changing it to static could fix your problem.
There is an annotation Singleton to change this behavior. In this case the resource will be managed as singleton and not in request scope. Here is a sample:
#Singleton
#Path("/json/messages")
public class JSONMessages {
(...)
}
Otherwise, be careful of concurrent accesses on your list. See this question for more details: java concurrent Array List access.
Hope it helps you,
Thierry

Related

Display Message to User instead of empty JSON on HTML when records are empty in the database

I have an application where I have an html page which takes user input through a textbox.This is a REST Spring Framework and is divided as Controller, Entity, Service, Repository, View and the main application class.
I take an input value and search in the Mongodb database, If the value is present, I return the entity object from Service to Controller. The controller returns the same Entity View object.- PersonView in this case. I get a JSON Data.
The above scenario works well as long as there are records in the database. In case if the record is not present, it returns an empty JSON. My Controller returns Person View Object and I do not wish to change the signature and make the return type as String since in that case it returns the address on my HTML page.
Considering this, how should I handle the case when there are no records in the database and I wish to display a message on this same HTML page saying there are no records available.
I tried throwing an exception but in this case too, how Do I display message on my HTML considering that my Controller returns JSON object and I do not wish to change its signature?
Controller Class is as below:
public PersonView searchPerson(#PathVariable String pname) {
List<Person> pList= PersonService.searchPerson(pname);
PersonView personView = new PersonView();
personView.setPersonView(pList);
return personView;
EDIT:
Here is the function from personView Class that I call in Controller:
public List<Person> setPersonView() {
this.personView = personView;
}
Here is the service Impl class:
public List<Person> searchPerson(String name) throws Exception {
List<Person> personlist= new ArrayList<Person>();
personlist = personRepository.findByName(name);
if (personlist.isEmpty())
throw new Exception("Records not found in the the database");
return personlist;
}
Create a custom Exception class:
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(String message) {
super(message);
}
}
Now, in you controller code:
public List<Person> searchPerson(String name) {
List<Person> personlist= new ArrayList<Person>();
personlist = personRepository.findByName(name);
if (personlist.isEmpty()) {
throw new EntityNotFoundException("Records not found in the the database");
}
return personlist;
}
After that you can try something like this in you controller class:
private static final MappingJacksonJsonView JSON_VIEW = new MappingJacksonJsonView();
#ExceptionHandler(EntityNotFoundException.class)
public ModelAndView handleNotFoundException( Exception ex )
{
return new ModelAndView(JSON_VIEW, "error", new ErrorMessage("No Record in Db") );
}
Your ErrorMessage class can be a simple POJO:
public class ErrorMessage {
private String message;
ErrorMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
Although already answered, I will add some points here.
Please note that at some point of time you will have a requirement to send the
headers, Response body (with different Objects). So consider using ResponseEntity Object which will be a wrapper to your List. Here is the sample code.
public ResponseEntity<List<Person>> searchPerson(String name) {
List<Person> personlist= new ArrayList<Person>();
personlist = personRepository.findByName(name);
if (personlist.isEmpty()) {
return new ResponseEntity(new EntityNotFoundException("Records not found in the the database"), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity(personlist , HttpStatus.OK);
}
Response Entity Object provides flexibility to greater extent. Read the documentation here.
https://docs.spring.io/spring/docs/current/javadocapi/org/springframework/http/ResponseEntity.html

Forward JSON POST request from one REST API to another

I have the following situation:
My REST API one:
#RestController
#RequestMapping("/controller1")
Public Class Controller1{
#RequestMapping(method = RequestMethod.POST)
public void process(#RequestBody String jsonString) throws InterruptedException, ExecutionException
{
............
}
}
JSON POST request, request1, for the REST API(Controller1):
{
"key1":"value1",
"key2":"value2"
}
My REST API two:
#RestController
#RequestMapping("/controller2")
Public Class Controller2{
#RequestMapping(method = RequestMethod.POST)
public void process(#RequestBody String jsonString) throws InterruptedException, ExecutionException
{
............
}
}
JSON request, request2, for the REST API(Controller2):
{
"key1":"value1",
"key2":"value2",
"key3":"value3"
}
I have several such "primitive" requests.
Now, I am expecting a JSON request, let's call it request3, which is a combination of such "primitive" queries- something that looks like below:
{
{
"requestType":"requestType1",
"request":"[{"key1":"value1","key2":"value2"}]"
},
{
"requestType":"requestType2",
"request":"[{"key1":"value1","key2":"value2","key3":"value3"}]"
}
}
Here, I need to trigger the respective API (one or two) upon identifying the query type. I wanna know how I can forward the request to the corresponding REST API. I wrote the REST API for request3 like below:
#RestController
#RequestMapping("/controller3")
Public Class Controller3{
#RequestMapping(method = RequestMethod.POST)
public void process(#RequestBody String jsonString) throws InterruptedException, ExecutionException
{
..................
..................
switch(request){
case request1: //how to call REST API 1?
case request2: //how to call REST API 2?
}
}
}
You can call a utility method which posts request to controller using Rest Template as below. Since you are using POST method it's easy to send parameters using Rest Template. You may need to edit this code a bit to work in your environment with exact syntax.
#RequestMapping( value= "/controller3" method = RequestMethod.POST)
public #ResponseBody void process(#RequestBody String jsonString){
String request = requestType //Get the request type from request
String url = "";
MultiValueMap<String, String> params= null;
switch(request){
case request1: //how to call REST API 1?
url = "/controller1";
params = request1param //Get the parameter map from request
case request2: //how to call REST API 2?
url = "/controller2";
params = request2Param //Get the parameter map from request
}
//Now call the method with parameters
getRESTResponse(url, params);
}
private String getRESTResponse(String url, MultiValueMap<String, String> params){
RestTemplate template = new RestTemplate();
HttpEntity<MultiValueMap<String, String>> requestEntity=
new HttpEntity<MultiValueMap<String, String>>(params);
String response = "";
try{
String responseEntity = template.exchange(url, HttpMethod.POST, requestEntity, String.class);
response = responseEntity.getBody();
}
catch(Exception e){
response = e.getMessage();
}
return response;
}
Redirect from one controller method to another controller method
Alternatively you also can call the rest method using Rest Template
Spring MVC - Calling a rest service from inside another rest service
You may find how to send POST request with params in this post
https://techie-mixture.blogspot.com/2016/07/spring-rest-template-sending-post.html

HttpClient.PostAsJsonAsync content empty

I'm trying to send a complex data type from one process to another using ASP.net MVC. For some reason the receiving end always receives blank (zero/default) data.
My sending side:
static void SendResult(ReportResultModel result)
{
//result contains valid data at this point
string portalRootPath = ConfigurationManager.AppSettings["webHost"];
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(portalRootPath);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage resp = client.PostAsJsonAsync("Reports/MetricEngineReport/MetricResultUpdate", result).Result;
if (!resp.IsSuccessStatusCode) {
//I've confirmed this isn't happening by putting a breakpoint in here.
}
}
My receiving side, in a different class, running in a different process on my local machine:
public class MetricEngineReportController : Controller
{
...
[HttpPost]
public void MetricResultUpdate(ReportResultModel result)
{
//this does get called, but
//all the guids in result are zero here :(
}
...
}
My model is a bit complicated:
[Serializable]
public class ReportResultModel
{
public ReportID reportID {get;set;}
public List<MetricResultModel> Results { get; set; }
}
[Serializable]
public class MetricResultModel
{
public Guid MetricGuid { get; set; }
public int Value { get; set; }
public MetricResultModel(MetricResultModel other)
{
MetricGuid = other.MetricGuid;
Value = other.Value;
}
public MetricResultModel(Guid MetricGuid, int Value)
{
this.MetricGuid = MetricGuid;
this.Value = Value;
}
}
[Serializable]
public struct ReportID
{
public Guid _topologyGuid;
public Guid _matchGuid;
}
Any idea why the data's not arriving?
Any help would be much appreciated...
P.S. For some reason I can't seem to catch the http POST message on fiddler, not sure why that is.
Try using "[FromBody]" parameter in Controller's Action. As you post data is passed to body not in url.
[HttpPost]
public void MetricResultUpdate([FromBody] ReportResultModel result)
{
//this does get called, but
//all the guids in result are zero here :(
}
The problem was twofold:
I needed to specify the type in my JSON post like this:
HttpResponseMessage resp = client.PostAsJsonAsync<MetricResultModel>("Reports/MetricEngineReport/MetricResultUpdate", result.Results[0]).Result;
The components of my model did not have default constructors, which is necessary for the JSON deserialization on the receiving end.
I just had the same problem. It seems that the content-length header is set to 0 when using the default PostAsJsonAsync extension method, which causes the server to ignore the request body.
My solution was to install the System.Net.Http.Json nuget package that uses the new System.Text.Json serializer.
When you add using System.Net.Http.Json;, you should be able to use the new extension method PostAsJsonAsync that works (sets the content-length header) properly.
namespace System.Net.Http.Json
{
public static class HttpClientJsonExtensions
{
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(this HttpClient client, string? requestUri, TValue value, CancellationToken cancellationToken)
{
return client.PostAsJsonAsync(requestUri, value, null, cancellationToken);
}
}
}

WcfFacility and Sequence contains no elements error?

I have wcf library with service contracts and implementations.
[ServiceContract]
public interface IServiceProtoType
{
[OperationContract]
Response GetMessage(Request request);
[OperationContract]
String SayHello();
}
[DataContract]
public class Request
{
private string name;
[DataMember]
public string Name
{
get { return name; }
set { name = value; }
}
}
[DataContract]
public class Response
{
private string message;
[DataMember]
public string Message
{
get { return message; }
set { message = value; }
}
}
public class MyDemoService : IServiceProtoType
{
public Response GetMessage(Request request)
{
var response = new Response();
if (null == request)
{
response.Message = "Error!";
}
else
{
response.Message = "Hello, " + request.Name;
}
return response;
}
public string SayHello()
{
return "Hello, World!";
}
}
I have windows service project that references this library, where MyService is just an empty shell that inherits ServiceBase. This service is installed and running under local system.
static void Main()
{
ServiceBase.Run(CreateContainer().Resolve());
}
private static IWindsorContainer CreateContainer()
{
IWindsorContainer container = new WindsorContainer();
container.Install(FromAssembly.This());
return container;
}
public class ServiceInstaller : IWindsorInstaller
{
#region IWindsorInstaller Members
public void Install(IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
string myDir;
if (string.IsNullOrEmpty(AppDomain.CurrentDomain.RelativeSearchPath))
{
myDir = AppDomain.CurrentDomain.BaseDirectory;
}
else
{
myDir = AppDomain.CurrentDomain.RelativeSearchPath;
}
var wcfLibPath = Path.Combine(myDir , "WcfDemo.dll");
string baseUrl = "http://localhost:8731/DemoService/{0}";
AssemblyName myAssembly = AssemblyName.GetAssemblyName(wcfLibPath);
container
.Register(
AllTypes
.FromAssemblyNamed(myAssembly.Name)
.InSameNamespaceAs<WcfDemo.MyDemoService>()
.WithServiceDefaultInterfaces()
.Configure(c =>
c.Named(c.Implementation.Name)
.AsWcfService(
new DefaultServiceModel()
.AddEndpoints(WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format(baseUrl,
c.Implementation.Name)
)))), Component.For<ServiceBase>().ImplementedBy<MyService>());
}
#endregion
}
In Client Console app I have the following code and I am getting the following error:
{"Sequence contains no elements"}
static void Main(string[] args)
{
IWindsorContainer container = new WindsorContainer();
string baseUrl = "http://localhost:8731/DemoService/{0}";
container.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero);
container
.Register(
Types
.FromAssemblyContaining<IServiceProtoType>()
.InSameNamespaceAs<IServiceProtoType>()
.Configure(
c => c.Named(c.Implementation.Name)
.AsWcfClient(new DefaultClientModel
{
Endpoint = WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format(baseUrl,
c.Name.Substring(1)))
})));
var service1 = container.Resolve<IServiceProtoType>();
Console.WriteLine(service1.SayHello());
Console.ReadLine();
}
I have an idea what this may be but you can stop reading this now (and I apologize for wasting your time in advance) if the answer to the following is no:
Is one (or more) of Request, Response, or MyDemoService in the same namespace as IServiceProtoType?
I suspect that Windsor is getting confused about those, since you are doing...
Types
.FromAssemblyContaining<IServiceProtoType>()
.InSameNamespaceAs<IServiceProtoType>()
... and then configuring everything which that returns as a WCF client proxy. This means that it will be trying to create proxies for things that should not be and hence a Sequence Contains no Elements exception (not the most useful message IMHO but crushing on).
The simple fix would be just to put your IServiceProtoType into its own namespace (I often have a namespace like XXXX.Services for my service contracts).
If that is not acceptable to you then you need to work out another way to identify just the service contracts - take a look at the If method for example or just a good ol' Component.For perhaps.

Getting and using remote JSON data

I'm working on a little app and using GWT to build it.
I just tried making a request to a remote server which will return a response as JSON.
I've tried using the overlay types concept but I couldn't get it working. I've been changing the code around so its a bit off from where the Google GWT tutorials left.
JavaScriptObject json;
public JavaScriptObject executeQuery(String query) {
String url = "http://api.domain.com?client_id=xxxx&query=";
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET,
URL.encode(url + query));
try {
#SuppressWarnings("unused")
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
// violation, etc.)
}
public void onResponseReceived(Request request,
Response response) {
if (200 == response.getStatusCode()) {
// Process the response in response.getText()
json =parseJson(response.getText());
} else {
}
}
});
} catch (RequestException e) {
// Couldn't connect to server
}
return json;
}
public static native JavaScriptObject parseJson(String jsonStr) /*-{
return eval(jsonStr );
;
}-*/;
In the chrome's debugger I get umbrellaexception, unable to see the stack trace and GWT debugger dies with NoSuchMethodError... Any ideas, pointers?
You may have a look to GWT AutoBean framework.
AutoBean allow you to serialize and deserialize JSON string from and to Plain Old Java Object.
For me this framework became essential :
Code is cleaner than with JSNI objects (JavaScript Native Interface)
No dependancy with Framework not supported by Google (like RestyGWT)
You just define interfaces with getters and setters :
// Declare any bean-like interface with matching getters and setters,
// no base type is necessary
interface Person {
Address getAddress();
String getName();
void setName(String name):
void setAddress(Address a);
}
interface Address {
String getZipcode();
void setZipcode(String zipCode);
}
Later you can serialize or deserialize JSON String using a factory (See documentation) :
// (...)
String serializeToJson(Person person) {
// Retrieve the AutoBean controller
AutoBean<Person> bean = AutoBeanUtils.getAutoBean(person);
return AutoBeanCodex.encode(bean).getPayload();
}
Person deserializeFromJson(String json) {
AutoBean<Person> bean = AutoBeanCodex.decode(myFactory, Person.class, json);
return bean.as();
}
// (...)
First post on Stack Overflow (!) : I hope this help :)
Use JsonUtils#safeEval() to evaluate the JSON string instead of calling eval() directly.
More importantly, don't try to pass the result of an asynchronous call (like RequestBuilder#sendRequest() back to a caller using return - use a callback:
public void executeQuery(String query,
final AsyncCallback<JavaScriptObject> callback)
{
...
try {
builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable caught) {
callback.onFailure(caught);
}
public void onResponseReceived(Request request, Response response) {
if (Response.SC_OK == response.getStatusCode()) {
try {
callback.onSuccess(JsonUtils.safeEval(response.getText()));
} catch (IllegalArgumentException iax) {
callback.onFailure(iax);
}
} else {
// Better to use a typed exception here to indicate the specific
// cause of the failure.
callback.onFailure(new Exception("Bad return code."));
}
}
});
} catch (RequestException e) {
callback.onFailure(e);
}
}
Generally, the workflow you're describing consists of four steps:
Make the request
Receive the JSON text
Parse the JSON in JavaScript objects
Describe these JavaScript objects using an overlay type
It sounds like you've already got steps 1 and 2 working properly.
Parse the JSON
JSONParser.parseStrict will do nicely. You'll be returned a JSONValue object.
This will allow you to avoid using your custom native method and will also make sure that it prevents arbitrary code execution while parsing the JSON. If your JSON payload is trusted and you want raw speed, use JSONParser.parseLenient. In either case, you need not write your own parser method.
Let's say that you're expecting the following JSON:
{
"name": "Bob Jones",
"occupations": [
"Igloo renovations contractor",
"Cesium clock cleaner"
]
}
Since you know that the JSON describes an object, you can tell the JSONValue that you're expecting to get a JavaScriptObject.
String jsonText = makeRequestAndGetJsonText(); // assume you've already made request
JSONValue jsonValue = JSONParser.parseStrict(jsonText);
JSONObject jsonObject = jsonValue.isObject(); // assert that this is an object
if (jsonObject == null) {
// uh oh, it wasn't an object after
// do error handling here
throw new RuntimeException("JSON payload did not describe an object");
}
Describe as an overlay type
Now that you know that your JSON describes an object, you can get that object and describe it in terms of a JavaScript class. Say you have this overlay type:
class Person {
String getName() /*-{
return this.name;
}-*/;
JsArray getOccupations() /*-{
return this.occupations;
}-*/;
}
You can make your new JavaScript object conform to this Java class by doing a cast:
Person person = jsonObject.getJavaScriptObject().cast();
String name = person.getName(); // name is "Bob Jones"
Using eval is generally dangerous, and can result in all kinds of strange behavior, if the server returns invalid JSON (note, that it's necessary, that the JSON top element is an array, if you simply use eval(jsonStr)!). So I'd make the server return a very simple result like
[ "hello" ]
and see, if the error still occurs, or if you can get a better stack trace.
Note: I assume, that the server is reachable under the same URL + port + protocol as your GWT host page (otherwise, RequestBuilder wouldn't work anyway due to Same Origin Policy.)
You actually don't need to parse the JSON, you can use native JSNI objects (JavaScript Native Interface).
Here's an example I pulled from a recent project doing basically the same thing you're doing:
public class Person extends JavaScriptObject{
// Overlay types always have protected, zero argument constructors.
protected Person(){}
// JSNI methods to get stock data
public final native String getName() /*-{ return this.name; }-*/;
public final native String getOccupation() /*-{ return this.occupation; }-*/;
// Non-JSNI methods below
}
and then to retrieve it like so:
/**
* Convert the string of JSON into JavaScript object.
*
*/
private final native JsArray<Person> asArrayOfPollData(String json) /*-{
return eval(json);
}-*/;
private void retrievePeopleList(){
errorMsgLabel.setVisible(false);
String url = JSON_URL;
url = URL.encode(url);
RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, url);
try{
#SuppressWarnings("unused")
Request request = builder.sendRequest(null, new RequestCallback() {
#Override
public void onResponseReceived(Request req, Response resp) {
if(resp.getStatusCode() == 200){
JsArray<Person> jsonPeople = asArrayOfPeopleData(resp.getText());
populatePeopleTable(people);
}
else{
displayError("Couldn't retrieve JSON (" + resp.getStatusText() + ")");
}
}
#Override
public void onError(Request req, Throwable arg1) {
System.out.println("couldn't retrieve JSON");
displayError("Couldn't retrieve JSON");
}
});
} catch(RequestException e) {
System.out.println("couldn't retrieve JSON");
displayError("Couldn't retrieve JSON");
}
}
So essentially you're casting the response as an array of JSON Objects. Good stuff.
More info here: http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsJSNI.html