how to receive Dictionary in WebAPI from javascript json - javascript

I have this controller function in WebAPI:
public class EntityController : APIController
{
[Route("Get")]
public HttpResponseMessage Get([FromUri]Dictionary<string, string> dic)
{ ... }
}
and my request, in javascript, looks like this:
{
"key1": "val1",
"key2": "val2",
"key3": "val3"
},
but the parse failed. is there a way to make this work without writing to much code? Thanks
my full request:
http://localhost/Exc/Get?dic={"key1":"val1"}

You could use a custom model binder:
public class DicModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != typeof(Dictionary<string, string>))
{
return false;
}
var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (val == null)
{
return false;
}
string key = val.RawValue as string;
if (key == null)
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Wrong value type");
return false;
}
string errorMessage;
try
{
var jsonObj = JObject.Parse(key);
bindingContext.Model = jsonObj.ToObject<Dictionary<string, string>>();
return true;
}
catch (JsonException e)
{
errorMessage = e.Message;
}
bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Cannot convert value: " + errorMessage);
return false;
}
}
And then use it:
public class EntityController : APIController
{
[Route("Get")]
public HttpResponseMessage Get([ModelBinder(typeof(DicModelBinder))]Dictionary<string, string> dic)
{ ... }
}
In the ModelBinder I used the Newtonsoft.Json library to parse the input string, then converted it to Dictionary. You could implement a different parsing logic.

See here ... with some adaptations to make. I think your difficulties are in how to call the URL.
Complex type is getting null in a ApiController parameter

Related

How to map html form data to a Spring Boot model containing a composite key?

I have popup form in my html that looks like this:
<dialog id="favDialog">
<div id="feedback"></div>
<form id="add_watchlist_symbol_form">
<label for="symbol">Enter Symbol:</label>
<input type="text" class="form-control" id="symbol" placeholder="SYMB"/><br><br>
<button type="submit" class="btn btn-default" id="add-watchlist-symbol-btn">Add</button>
</form>
<button id="cancelBtn" value="cancel">Cancel</button>
</dialog>
The dialog pops up successfully when I click a button.
The dialog contains a button called Add. It's click event is handled by javascript which sends an ajax POST request containing the form field values to Spring Boot like this:
function submit_watchlist_symbol() {
console.log("Im in submit_watchlist_symbol");
var formData = {
symbol: $("#symbol").val(),
name: "My Portfolio"
}
//$("#btn-search").prop("disabled", true);
$.ajax({
type: "POST",
contentType: "application/json",
url: "/api/v1/AddSymbolToWatchlist",
data: JSON.stringify(formData),
dataType: 'json',
success: function (result) {
if(result.status=="Done") {
$('#feedback').html(result.data.symbol +" added.");
}
else {
$('#feedback').html("<strong>Error</strong>");
}
console.log("ERROR: ",e);
},
error: function (e) {
alert("Error!")
console.log("ERROR: ",e);
}
});
// Reset FormData after Posting
resetData();
}
When I click that button I get Spring Boot error:
Resolved
[org.springframework.http.converter.HttpMessageNotReadableException:
JSON parse error: null; nested exception is
com.fasterxml.jackson.databind.JsonMappingException: N/A at [Source:
(PushbackInputStream); line: 1, column: 11] (through reference chain:
net.tekknow.moneymachine.model.Watchlist["symbol"])]
I suspect the form data is not being mapped correctly to the Watchlist.java model due to the model containing a composite key, like this:
#Entity
#Table(name = "watchlist")
public class Watchlist {
#EmbeddedId
public WatchlistId watchlistId;
public String getSymbol() {
return watchlistId.getSymbol();
}
public void setSymbol(String symbol) {
watchlistId.setSymbol(symbol);
}
public String getName() {
return watchlistId.getName();
}
public void setName(String watchlistName) {
watchlistId.setName(watchlistName);
}
public String toString() {
return "watchlist:symbol=" +getSymbol() +", name="+getName();
}
}
where watchlistId contains the symbol and name, like this:
#Embeddable
public class WatchlistId implements Serializable {
#Column(name="symbol")
private String symbol;
#Column(name="name")
private String name;
WatchlistId() {
}
WatchlistId(String symbol, String name) {
this.symbol = symbol;
this.name = name;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WatchlistId that = (WatchlistId) o;
return Objects.equals(symbol, that.symbol) && Objects.equals(name, that.name);
}
#Override
public int hashCode() {
return Objects.hash(symbol, name);
}
}
Here is the Spring Boot controller that handles the request:
#PostMapping("/AddSymbolToWatchlist")
#ResponseBody
public AddWatchlistSymbolResponse addSymbolToWatchlist(#RequestBody Watchlist watchlist){
System.out.println("made it to AddWatchlistSymbolResponse");
// Create Response Object
AddWatchlistSymbolResponse response = new AddWatchlistSymbolResponse("Done", watchlist);
return response;
}
The AddWatchlistSymbolResponse class looks like this:
public class AddWatchlistSymbolResponse {
private String status;
private Object data;
public AddWatchlistSymbolResponse(){
}
public AddWatchlistSymbolResponse(String status, Object data){
this.status = status;
this.data = data;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
Suggestions?
I figured it out. I changed the controller to this:
#PostMapping(value = "/AddSymbolToWatchlist")
#ResponseBody
public WatchlistIdResponse addSymbolToWatchlist(#RequestBody WatchlistId watchlistId){
System.out.println("made it to AddWatchlistSymbolResponse");
watchlistService.addSymbolToWatchlist(watchlistId);
// Create Response Object
WatchlistIdResponse response = new WatchlistIdResponse("Done", watchlistId);
return response;
}
And created a separate response for WatchlistId called WatchlistIdResponse.java:
package net.tekknow.moneymachine.model;
public class WatchlistIdResponse {
private String status;
private Object data;
public WatchlistIdResponse() {
}
public WatchlistIdResponse(String status, Object data) {
this.status = status;
this.data = data;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
The reason is that the Watchlist class contains only the WatchlistId property. WatchlistId contains the symbol and name properties that make up the composite index.

Passing Object to Java from AngularJS

i'm in trouble with this problem.
I've a Javascript structur like this:
$scope.setting= {
enabled: false,
host:"",
port:"",
user:"",
pwd:"",
path:"/",
filePrefix:"",
type:"",
sendInterval:"",
dataPeriod:"",
compression:false,
subscription:[]
};
In the controller i modify the subscription array, but when i pass it to the java code:
$http.post('/api/testAndSetFTPSetting', $scope.setting)
.success(function (data) {
console.log(data);
})
.error(function (data, status, header, config) {
});
the subscription array is null.
Here the API
#RequestMapping(value = {"/api/testAndSetFTPSetting"}, method={RequestMethod.POST})
#ResponseBody
public boolean testAndSetFTPSetting(FTPConfiguration ftp) throws JAXBException {
System.out.println(ftp.getSubscribtion().size()); // here i've ever 0 and ftp.getSubscribtion() return me null
return true;
}
Here the Java Class who controls the object:
#XmlRootElement(name="FTPconfiguration")
#XmlAccessorType (XmlAccessType.FIELD)
public class FTPConfiguration{
boolean enabled = false;
String host="127.0.0.1";
int port=22;
String user="root";
String pwd="";
String path="/";
String filePrefix="data";
FTPType type=FTPType.SFTP;
int sendInterval=15;
int dataPeriod=5;
boolean compression=false;
#XmlElementWrapper(name="subscriptions")
List<String> subscription = new LinkedList<String>();
public FTPConfiguration() {
}
public FTPConfiguration(boolean enabled,String host, int port, String user, String pwd, String path, String filePrefix,
FTPType type, int sendInterval, int dataPeriod, boolean compression, List<String> subscription) {
super();
this.host = host;
this.port = port;
this.user = user;
this.pwd = pwd;
this.path = path;
this.filePrefix = filePrefix;
this.type = type;
this.sendInterval = sendInterval;
this.dataPeriod = dataPeriod;
this.compression = compression;
if(subscription != null)
this.subscription.addAll(subscription);
}
// setter and getter method
Where is my fault?
Finally solved!!! The problem was that the javascript array in java is a comma separated String. For this the value that i received was null!
EX
JavaScript OBJ
var arr = ["1", "2", "3"];
$http.post('someUrl', arr)...
Java
#RequestMapping(value = {"/someUrl"}, method={RequestMethod.POST})
public void foo(String s) { // s will be = "1,2,3"
}

Object POSTed to Wcf web service request is null

This is my .Net Wcf WebService Service1.cs
[DataContract]
public class CompositeType
{
string degree;
string Stre;
string YearOfPass;
string Institute;
string StatusMessage;
string CheckStatus;
[DataMember]
public string deg
{
get { return degree; }
set { degree = value; }
}
[DataMember]
public string stream
{
get
{ return Stre; }
set
{ Stre = value; }
}
[DataMember]
public string yop
{
get
{ return YearOfPass; }
set
{ YearOfPass = value; }
}
[DataMember]
public string inst
{
get
{ return Institute; }
set
{ Institute = value; }
}
[DataMember]
public string StatusMsg
{
get
{ return StatusMessage;}
set
{ StatusMessage = value; }
}
[DataMember]
public string check
{
get
{ return CheckStatus; }
set
{ CheckStatus = value; }
}
}
Here, in Wcf, variables and methods are created. I used AngularJS GET method to call this Wcf Service. The output is Perfect. But using POST method in AngularJS, I get: StatusMsg= "Request object is nullTestCORS_1101.CompositeType"
Here is the AngularJS code:
var app = angular.module('starter', []);
app.controller('customerCtrl',function($scope,$http){
var Composite={"deg":"s","stream":"m","inst":"t","yop":"w"};
console.log(Composite);
$http({
url:'http://192.168.1.50/TestSubCors/Service1.svc/GetDataUsingDataContract',
method: 'POST',
data:Composite,
headers:{'Content-Type':'application/json;charset=utf-8'}
}).then(function(response){
var parsed_data = angular.toJson(response);
console.log("Success")
console.log(parsed_data);
$scope.events=parsed_data;
}),function(response){
$log.error('failure loading', errorresponse);
}
});
Why I am getting this null request object?

Trying to pass an object to a spring controller using Jquery getJSON

I'm trying to pass a javascript object
var questionConstraintLineItem = {
"string1": "bhanu",
"string2": "prasad"
};
Using jQuery getJson
$.getJSON("/SafeSiteLive/common/createTaskWizard/saveTask.json", {
questionConstraintLineItem: questionConstraintLineItem
}, function (data)
{
try {
dialog.dialog("close");
getGroups();
} catch (e) {
alert("An exception occurred in the script. Error name: " + e.name + ". Error message: " + e.message);
}
});
To my spring controller
#RequestMapping(value = "common/createTaskWizard/saveTask.json", method=RequestMethod.GET)
public #ResponseBody void saveTask(
QuestionConstraintLineItem questionConstraintLineItem) {
rest of the code...
I have tried using #RequestParam("questionConstraintLineItem") also.
Neither method works. Without the #RequestParam the request goes through to the server but the object is not filled with the data.
Am I doing this the wrong way?
Here is the QuestionConstaintLineItem POJO
public class QuestionConstraintLineItem implements Serializable{
private String string1;
private String string2;
public String getString1() {
return string1;
}
public void setString1(String string1) {
this.string1 = string1;
}
public String getString2() {
return string2;
}
public void setString2(String string2) {
this.string2 = string2;
}
}
Here is the error I get when I use the #RequestParam.

JSON serialization - how to unquote a property value?

Given a class A ...
public class A {
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
string jsonString = JsonConvert.SerializeObject(
new A() {
Prop1 = "ABC",
Prop2 = "$.jqplot.DateAxisRenderer" }
);
jsonString contains...
"{
\"Prop1\":\"ABC\",
\"Prop2\":\"$.jqplot.DateAxisRenderer\"
}";
Question:
How can I unquote Prop2?
i.e. I want jsonString to contain...
"{
\"Prop1\":\"ABC\",
\"Prop2\":$.jqplot.DateAxisRenderer
}";
so that Prop2 is evaluated (on the client) as a reference and not a string
If you want to remove the quotes from Prop2, you can write a JSON.NET JsonConverter for the type and output the property value as 'raw'.
However (and this is important), your output will no longer be valid JSON.
If you're happy with this hybrid solution, some example code is as follows (assuming you've already referenced JSON.NET in your project):
namespace JsonRawTest
{
public class AConverter : JsonConverter
{
public override bool CanRead { get { return false; } }
public override bool CanWrite { get { return true; } }
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
A obj = value as A;
writer.WriteStartObject();
writer.WritePropertyName("Prop1");
writer.WriteValue(obj.Prop1);
writer.WritePropertyName("Prop2");
writer.WriteRawValue(obj.Prop2);
writer.WriteEndObject();
}
public override bool CanConvert(Type objectType)
{
return typeof(A).IsAssignableFrom(objectType);
}
}
public class A
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var a = new A
{
Prop1 = "Some first value",
Prop2 = "$.jqplot.DateAxisRenderer"
};
string json = JsonConvert.SerializeObject(a,
new JsonConverter[] { new AConverter() });
...
}
}
}
You can pass it to the client as a string and then use the eval() function to parse the string like so:
var str = "alert('hello')";
eval(str); //This will execute the alert method.
var str2 = "(function() { return true; })()";
var returned = eval(str2); //Holds value of true

Categories

Resources