I have been Googling and trying to get this to work for hours...The problem is the server is not receiving data as JSON but as text. This is the POJO
package my.package;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class TestConfig {
private String firmID;
private String traderID;
private String userID;
public TestConfig() {};
...
}
A Javascript client which contains:
function callbackForTest(response) {
console.log("Call to callbackForTest");
if (response.state == "opening" && response.status == 200) {
//push request data
if (connectedEndpoint[0] == null) {
console.log("[DEBUG] Connected endpoint for " + value + "is null!");
//disable button
$(value).attr('disabled','');
$.atmosphere.unsubscribe();
return false;
}
// push ( POST )
connectedEndpoint[0].push(JSON.stringify(
{
operation : "RUN",
firmID : $('#firmID').val(),
userID : $('#userID').val(),
traderID : $('#traderID').val(),
protocol : $('#protocol').val(),
group1 :
}
));
}
}
function subscribeUrl(jobName, call, transport) {
var location = subscribePath + jobName.id;
return subscribeAtmosphere(location, call, transport);
}
function globalCallback(response) {
if (response.state != "messageReceived") {
return;
}
}
function subscribeAtmosphere(location, call, transport) {
var rq = $.atmosphere.subscribe(location, globalCallback, $.atmosphere.request = {
logLevel : 'debug',
transport : transport,
enableProtocol: true,
callback : call,
contentType : 'application/json'
});
return rq;
}
function sendMessage(connectedEndpoint, jobName) {
var phrase = $('#msg-' + jobName).val();
connectedEndpoint.push({data: "message=" + phrase});
}
// Run Test handlers
$("input[name='runButtons']").each(function(index, value){
$(value).click(function(){
//disable button
$(value).attr('disabled','disabled');
// connect (GET)
connectedEndpoint[index] = subscribeUrl(value, callbackForTest, transport);
});
});
I have included the libs shown in this screenshot:
LIBS
And this is my web.xml (part of it)
com.sun.jersey.api.json.POJOMappingFeature
true
The Jersey resource
#Path("/subscribe/{topic}")
#Produces({MediaType.APPLICATION_JSON, "text/html;charset=ISO-8859-1", MediaType.TEXT_PLAIN})
public class Subscriber {
private static final Logger LOG = Logger.getLogger(Subscriber.class);
#PathParam("topic")
private Broadcaster topic;
#GET
public SuspendResponse<String> subscribe() {
LOG.debug("GET - OnSubscribe to topic");
SuspendResponse<String> sr = new SuspendResponse.SuspendResponseBuilder<String>().broadcaster(topic).outputComments(true)
.addListener(new EventsLogger()).build();
return sr;
}
#POST
#Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN, MediaType.TEXT_HTML})
#Broadcast
public Broadcastable publish( TestConfig t) {
LOG.debug("POST");
String s = t.getFirmID();
return new Broadcastable(s, "", topic);
}
I can subscribe OK. When I try to push to the server, I get this exception:
A message body reader for Java class com.mx.sailcertifier.TestConfig, and Java type class com.mx.sailcertifier.TestConfig, and MIME media type text/plain was not found.
Why is it sending plain text if I set the content type to application/json? What is the correct way to get the Jersey resource to read the JSON?
I finally got this working with two changes:
After looking at the sample here, I added this init-param to the AtmosphereServlet in the web.xml to resolve the text/plain problem in Tomcat:
<init-param>
<param-name>org.atmosphere.websocket.messageContentType</param-name>
<param-value>application/json</param-value>
</init-param>
I didn't see this anywhere documented in the Atmosphere docs. It would have saved a lot of time had it been, but documentation-wise the API is unfortunately disorganized and lacking.
Also, I needed to use the jersey-bundle jar make sure that everything Jersey related is included, including as the jersey-json.jar. After that, it worked! Hope this helps someone else who may have been stuck with the same or similar problem.
Related
I exposed a web service on Apache Camel.
Endpoint:
https://company.aaaa.com/persons/{zone}/{personId}/equipments?equipmentId=value (named webservice A)
The web service A takes this parameters:
-zone de type string : path param
-personId de type integer : path param
-equipmentId de type string : request param
The web service A do many things and call many other web services but to keep things simple, I will focus only on the web service that fails.
so if the equipmentId is not null, the web service A call a web service B with this endpoint
https://company.bbbb.com/persons/{zone}/{personId}/equipments/{equipmentId}
It works when the equipmentId dosen't contain / and I got the right response.
But My problem is if equipmentId contains / caracter for example (equipmentId = AQCz/gIAJWsDACivB==)
It will fails with 404 not found because he can't find the resource.
So I encoded the equipmentId, store it in an exchange property called equipmentEncoded
and use the toD camel pattern to invoke the endpoint.
Then when I called the web service A :
https://company.aaaa.com/persons/zone/56809546/equipments?equipmentId=AQCz/gIAJWsDACivB==
I got an error 404 : Failed to invoke the endpoint https://company.bbbb.com/persons/zone/56809546/equipments/AQCz/gIAJWsDACivB==
When debugging : I do have an exchange property equipmentEncoded with right value encoded AQCz%2FgIAJWsDACivB%3D%3D
But I don't know why toD don't keep the encoded value of the exchange property equipmentEncoded
This is the algorithme of the web service A : (Just the part that generates error)
.process(setEquipmentIdPropertyProcessor)
.choice()
.when(exchangeProperty(TestConstants.EQUIPMENT_ID_REQUEST_PARAM_EXIST).isEqualTo(1))
.process(exchange -> {
var t = true;
})
.toD(getHTTPEndpointURL(companyBEndpoint, "persons/${header." + TestConstants.HEADER_ZONE_PARAM + "}/"
+ "${header." + TestConstants.HEADER_PERSON_ID_PARAM + "}/" + "equipments/"
+"${exchangeProperty." + TestConstants.EQUIPMENT_ENCODED + "}" ))
.endChoice()
.otherwise()
.process(exchange -> {
var t = true;
})
This the code of the processor setEquipmentIdPropertyProcessor
#Component
public class SetEquipmentIdPropertyProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
String equipmentParamValue =
(String)exchange.getIn().getHeader(TestConstants.HEADER_EQUIPMENT_PARAM);
if (StringUtils.isNotBlank(equipmentParamValue)){
exchange.setProperty(TestConstants.EQUIPMENT_ID_REQUEST_PARAM_EXIST, 1);
String equipmentEncoded = URLEncoder.encode(equipmentParamValue, StandardCharsets.UTF_8);
exchange.setProperty(TestConstants.EQUIPMENT_ENCODED, equipmentEncoded);
} else {
exchange.setProperty(TestConstants.EQUIPMENT_ID_REQUEST_PARAM_EXIST, 0);
}
}
}
so in the class SetEquipmentIdPropertyProcessor when the equipmentId request param is filled, I encode the equipmentId param and store the value in an exchange property.
Here is the code of the method getHttpEndpointURL to construct the url:
public String getHTTPEndpointURL(final EndpointProperty endpointConf, final String
uriPath) {
return endpointConf.getUrl() +
endpointConf.getPath() +
uriPath + "?bridgeEndpoint=true";
}
Here is the code of the classe TestConstants
public class TestConstants {
public static final String HEADER_ZONE_PARAM = "zone";
public static final String HEADER_PERSON_ID_PARAM = "personId";
public static final String HEADER_EQUIPMENT_PARAM = "equipment";
public static final String EQUIPMENT_ENCODED = "equipmentEncoded"; }
I would like that Camel invokes this url https://company.bbbb.com/persons/zone/56809546/equipments/AQCz%2FgIAJWsDACivB%3D%3D
instead of invoking this one : https://company.bbbb.com/persons/zone/56809546/equipments/AQCz/gIAJWsDACivB==
Can't handle exceptions occurs on server side by flash (flex) application.
Server on java, spring-boot-web, for handling exceptions uses org.zalando library.
On server, for example:
#ExceptionHandler(value = SecurityException.class)
public ResponseEntity securityViolation(Throwable e, NativeWebRequest request) {
log.error(e.getMessage(), e);
HttpServletRequest httpServletRequest = ((ServletWebRequest) request).getRequest();
ThrowableProblem problem = createBaseProblemBuilder(Error.SECURITY_ERROR, httpServletRequest)
.withStatus(Status.FORBIDDEN)
.withTitle("Unauthorized")
.withDetail(e.getMessage())
.build();
return create(problem, request);
}
private ProblemBuilder createBaseProblemBuilder(Error error, HttpServletRequest httpServletRequest) {
return Problem.builder()
.withType(URI.create(Error.BASE_ERROR_URL + error.getCode()))
.with("httpMethod", httpServletRequest.getMethod())
.withInstance(URI.create(httpServletRequest.getRequestURI()))
.with("requestTraceId", Long.toString(Thread.currentThread().getId()))
.with("timestamp", LocalDateTime.now());
}
On client (flex):
public function invokeCommand(url: String, requestBody: String = null): IThenable {
return new Promise(function (fulfill: Function = null, reject: Function = null): * {
invokeService(requestBody, _serverInfo.serviceUrl + url,
function (event: ResultEvent): void {
fulfill(event.result);
}, function (event: FaultEvent): void {
var response: Object = event.fault.content;
handleFault(response);
reject(response);
});
});
}
private function handleFault(response: Object): void {
var faultResponseDto: FaultResponseDto = new FaultResponseDto(response ? JSON.parse(response.toString()) : null);
... some code, but response already is empty
}
Expects, that event.fault.content contains data from server, but it always empty.
In browser network console response has payload, and contains all data from server in json.
Main question - how i can read fault payload in flash?
In debug I browse all in FaultEvent, but can't find nothing about needed data.
P.S. sorry for bad english...
Have been struggling for last few days with this error Authentication of type {http://service.soap.xcompany.com}AuthenticationHeader had undefined attribute {http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Id while invoking a service call from a C# WCF client (targeting .Net 4.5 framework) to a Java Soap Service hosted externally with end-to-end encryption (both client and service certificates are used). When I tested the service using SoapUI with a JKS file, request was processed successfully.
So to see what's difference between the two requests, I did the followings:
Used Fiddler Inspector to capture two requests, one from SoapUI which was successful and one from C# which failed with 500 error
Extracted these two Xml messages into two C# classes (named them RequestByJava and RequestByDotNet, respectively) using the VS2017 feature Edit/Paste Special/Paste Xml as Classes.
Use XmlSerializer to de-serialize the two requests into the two objects of the types created in 2) and compared their properties.
With the Soap error message in mind, I narrowed down the difference between two Authentication headers - interestingly there is one extra property "Id" in the RequestByDotNet object whereas the RequestByJava object does not have. And the 500 Soap error message seemed to indicate that there was a schema validation error due to that undefined element "Id"
Also noticed that the RequestByDotNet.Header.Security.BinarySecurityToken.ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" but RequestByJava (SoapUI) has a different ValueType "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1"
Another difference, not sure it matters, is that the Request from .net codes has a "mustunderstand" value under the Header.Security set to true while the one from Java does not.
My questions are:
Why is the difference?
How can this be fixed without having to write a Java client?
Some codes used binding and endpoint behavior:
private static CustomBinding BuildCustomBinding()
{
var binding = new CustomBinding();
var textMessageEncoding = new TextMessageEncodingBindingElement()
{
MessageVersion = MessageVersion.Soap11
};
var securityBindingElement =
SecurityBindingElement.CreateMutualCertificateBindingElement(
MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10, true);
binding.Elements.AddRange(textMessageEncoding, securityBindingElement, new HttpsTransportBindingElement());
return binding;
}
private static void CallAccountService()
{
//credential for test
const string applId = "testuser";
const string pwd = "password";
//for client certificate, import client.pfx to LocalMachine's Trusted Root Certification Authorities and make sure the thumbprint matches
var client = new NOLWSAccountSvc.WSAccountv1Client(BuildCustomBinding(), GetAccountServiceEndpointAddress());
client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine,
StoreName.Root, X509FindType.FindByThumbprint, "thumbprintvalue");
//for service certificate, import service-provider.cer to same store location and store name and make sure the thumbprint matches
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.Root,
X509FindType.FindByThumbprint, "thumprintvalue");
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust;
client.Open();
var header = new NOLWSAccountSvc.AuthenticationHeader()
{
application_id = applId,
password = pwd
};
var getActiveAccountsFunc = new NOLWSAccountSvc.getActiveAccounts() { applRef = "softact-dev", resetRows = true };
try
{
var response = client.getActiveAccounts(header, getActiveAccountsFunc);
Console.WriteLine(response.moreData);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
client.Close();
}
}
Thanks for your time! Your help will be highly appreciated.
#jdweng Yes, I did; here were two request bodies, first from .Net and 2nd from SoapUI:
.Net Request:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><h:Authentication u:Id="_2" xmlns:h="http://service.soap.xcompany.com" xmlns="http://service.soap.xcompany.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><application_id>testuserid</application_id><password>testpassword</password></h:Authentication><ActivityId CorrelationId="d7085e6f-b757-46e8-b3eb-319a51d568a3" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">00000000-0000-0000-0000-000000000000</ActivityId><VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo8DAzaQVkApDpl1Tc1YTHQwAAAAAMbeMEvBLCUqoD7kEDPHDKYukgggNOf5FtHBB/Sa7ggkACQAA</VsDebuggerCausalityData><o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><o:BinarySecurityToken u:Id="uuid-eb310312-396a-4d00-8922-f77de97138cb-3" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">MIIDYzCCAkugAwIBAgIEaGKzJDANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJ1czEPMA0GA1UEChMGU3ByaW50MREwDwYDVQQLEwhQcm9qZWN0czEMMAoGA1UECxMDQk1QMQwwCgYDVQQLEwNUUEExEzARBgNV</o:BinarySecurityToken><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="#_1"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>WCpRwVjx89ceVctR8lp9LNGKHeA=</DigestValue></Reference><Reference URI="#_2"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>8/PErh8BL9To5zazpP9CbPFTAa8=</DigestValue></Reference></SignedInfo><SignatureValue>hOtpz7lXvZPPbBD6sV1hxyx3Hc39vj0q2GYKMd8oQbgTbbuKC7QKcZOjktqUxayrzc6h/V0j7Kx3APPONe4F3A2581nK4AQ72yYonsaeXQW0yzSxW/VTsN04uoqCP6IpKXqlAz40VeWGUPJOeGthCKy/9A+NSuqS</SignatureValue><KeyInfo><o:SecurityTokenReference><o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-eb310312-396a-4d00-8922-f77de97138cb-3"/></o:SecurityTokenReference></KeyInfo></Signature></o:Security></s:Header><s:Body u:Id="_1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><getActiveAccounts xmlns="http://service.soap.xcompany.com"><applRef>dev</applRef><resetRows>false</resetRows></getActiveAccounts></s:Body></s:Envelope>
SoapUI Request:
(somehow it won't let me past whole xml here.. )
Well, my colleague helped me figure out way to remove the extra headers from the request before it was posted to the Java SOAP service endpoint - the key was to use IClientMessageInspector and implement some logic in the BeforeSendRequest to remove the unwanted headers that were rejected by the service provider; then add a custom FormattingBehavior class to inherit from IEndpointBheavior and in the IEndPointBehavior.ApplyClientBehavior, attach the MyClientMessageInspector; finally add the customer endpoint behavior to the web service client. Here are the codes:
Where and how to remove unwanted request headers:
public class MyClientMessageInspector : IClientMessageInspector
{
public MyClientMessageInspector(ServiceEndpoint endpoint)
{
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
//Console.WriteLine(request.ToString());
var lstUnwantedStuff = new[]
{
new KeyValuePair<string, string>("Action", "http://www.w3.org/2005/08/addressing"),
new KeyValuePair<string, string>("VsDebuggerCausalityData",
"http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink")
};
foreach (var kv in lstUnwantedStuff)
{
var indexOfUnwantedHeader = request.Headers.FindHeader(kv.Key, kv.Value);
if (indexOfUnwantedHeader>=0)
{
request.Headers.RemoveAt(indexOfUnwantedHeader);
}
}
...
Where and how to use the custom ClientMessageInspector:
internal class MyFaultFormatterBehavior : IEndpointBehavior
{
...
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyClientMessageInspector(endpoint));
}
}
Where and how to attach custom EndpointBehavior:
private static void CallAccountService()
{
var client = new WSAccountv1Client(BuildCustomBinding(), GetAccountServiceEndpointAddress());
//Set client certificate
client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine,
StoreName.Root, X509FindType.FindByThumbprint, "xxxxxxxxxx");
//for service certificate
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople,
X509FindType.FindByThumbprint, "xxxxxxxxxxxxxxxxy");
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust;
//add faultformattingbehavior so we can intercept the fault reply message
client.Endpoint.EndpointBehaviors.Add(new MyFaultFormatterBehavior());
client.Open();
var header = new AuthenticationHeader()
{
application_id = applId,
password = pwd
};
var getActiveAccountsFunc = new getActiveAccounts() { applRef = "test", resetRows = true };
try
{
//MyClientMessageInspector.BeforeSendRequest is entered when this called is made
var response = client.getActiveAccounts(header, getActiveAccountsFunc);
Console.WriteLine(response.moreData);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
client.Close();
}
}
What else?
In the proxy classes, need to set the Authentication ProtectionLevel to None while on the Service level it needs to be set as ProtectionLevel.Sign:
Request level:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(IsWrapped = false)]
public partial class getActiveAccountsRequest
{
[System.ServiceModel.MessageHeaderAttribute(Namespace = "http://service.xcompany.com"
, ProtectionLevel = System.Net.Security.ProtectionLevel.None
)]
public AuthenticationHeader Authentication;
Service (Interface) Level:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace = "http://service.xcompany.com",
ConfigurationName = "WSAccount"
, ProtectionLevel = ProtectionLevel.Sign
)]
public interface WSAccount
{
I have a working Jersey/Atmosphere/Guice application which has two Atmosphere Resources. The first is pretty much a clone of the example chat application:
#Path("/chat")
#AtmosphereService(broadcaster = JerseyBroadcaster.class, path = "/chat")
public class ChatResource {
#Suspend(contentType = "application/json")
#GET
public String suspend() {
return "";
}
#Broadcast(writeEntity = false)
#POST
#Produces("application/json")
public Response broadcast(Message message) {
return new Response(message.author, message.message);
}
}
The second is a test notification resource which will be sent server-side events:
#Path("/notifications")
#AtmosphereService(broadcaster = JerseyBroadcaster.class, path = "/notifications")
public class NotificationsResource {
#Suspend(contentType = "application/json")
#GET
public String suspend() {
return "";
}
}
Everything is wired up correctly and works fine. However in order for me to send a server side event I issue:
MetaBroadcaster.getDefault().broadcastTo("/*", new Response(...));
Clearly, this will send the broadcast message to both resources. What I want to do is send the server side events only to the notifications resource:
MetaBroadcaster.getDefault().broadcastTo("/notifications", new NotificationResponse(...));
However, that doesn't work. I always receive the following error:
org.atmosphere.cpr.MetaBroadcaster - No Broadcaster matches /notifications.
That's because there is only one broadcaster registered; the JerseyBroadcaster on /*.
The question is: how do I make it so that these two resources have different broadcasters with different IDs/Names?
In the resource, suspend using the channel you want (the 'true' parameter to lookup() forces the channel to be created if it doesn't exist):
#Suspend( contentType = MediaType.APPLICATION_JSON, period = MAX_SUSPEND_MSEC )
#GET
public Broadcastable suspend( #Context final BroadcasterFactory factory )
{
return new Broadcastable( factory.lookup( MY_CHANNEL, true ) );
}
In the other code, which can be pretty much anywhere, broadcast to that channel:
Broadcaster broadcaster = BroadcasterFactory.getDefault().lookup( MY_CHANNEL );
if( broadcaster != null ) {
broadcaster.broadcast( message );
}
If you're going to be broadcasting from a resource method, you can annotate it instead (as shown in ChatResource's broadcast() method).
Just inject Broadcaster using the #PathParam annotation:
private
#PathParam("topic")
Broadcaster topic;
You can also use the #Context annotation. Hope that help.
-- Jeanfrancois
Hi everyone this is my first question here, hope you can help me with this issue I'm having right now.
I want to send a JSON Object using JQuery to a Spring Controller.
The format of the JSON Object is as follows:
{"ssoArray":["21212", "231341"], "groupArray":["g10002", "g10003"]}
But I got the error message: the request sent by the client was syntactically incorrect
My Environment:
Spring 3.0.6
jackson 1.9.13
JBoss 4.2
JQuery code:
Update: Added the full code of the javascript method that makes the ajax call
function addRemoveAdmin(action, ssoArray, groupArray) {
var uri = actionPath + "/";
var jsonParameter = {"ssoArray":ssoArray, "groupArray":groupArray};
if(action == "add") {
uri = uri + addAdminAction;
} else {
uri = uri + removeAdminAction;
}
console.log(typeof jsonParameter);
$.ajax({
url:uri,
type:"POST",
data:jsonParameter,
contentType:"application/json; charset=utf-8",
dataType:"json",
success: function(){
alert(data);
}
});
}
Controller code:
#RequestMapping(value = "/addAdmin", method = RequestMethod.POST)
public String addAdmin(#RequestBody final AdminAndGroup personsAndGroups) throws Exception {
LOGGER.info("[RequestController] - addAdmin start");
LOGGER.info(personsAndGroups.toString());
return "OK";
}
Mapping class:
public class AdminAndGroup implements Serializable {
private static final long serialVersionUID = 9024455757311860269L;
private List<String> ssoArray;
private List<String> groupArray;
public AdminAndGroup(){}
public List<String> getSsoArray() {
return ssoArray;
}
public void setSsoArray(List<String> ssoArray) {
this.ssoArray = ssoArray;
}
public List<String> getGroupArray() {
return groupArray;
}
public void setGroupArray(List<String> groupArray) {
this.groupArray = groupArray;
}
#Override
public String toString() {
return "AdminAndGroup [ssoArray=" + ssoArray + ", groupArray="
+ groupArray + "]";
}
}
I have used java.util.List to map the arrays that come inside the JSON Object but I'm not sure if this is the right way to tackle the issue.
Also I have searched in Stack Overflow and I haven't found an example on how to map arrays inside a JSON Object.
Thanks in advance.
If you want to send json, you must convert your object to json. Otherwise, jQuery will convert it to a param string
data: JSON.stringify(jsonParameter)