My used stack
spring boot 1.5.6 realease
ajax jquery 3.3.1
My objective
I m trying to print some data into jasper report so I created a rest controller, I got the idea to send json data from front end and got it parsed thanks to jackson api into List of pojo then using the JRDataBean to process my report
My code
When pushing the print button I m sending this json array using ajax that I got from the chrome console by making it a global variable then using a copy ( atrick that I googled to get variable content as string )
here is my json
.
[ {
"codeInterne": 45,
"clientName": "TalcorpDZ",
"clientPhone": "+213778217469",
"codeExterne": "CLI201801",
"email": "talcorpdz#gmail.com",
"clientType": 0,
"clientEtat": 1,
"identifiant": "TalcorpDZ",
"contacts": [
{
"nom": "Taleb",
"prenom": "Mohammed Housseyn",
"telephonePortable": "04330256699",
"email": null
}
],
"adresses": [
{
"adress": "Batiments des enseignants Mohammed Khemisti",
"ville": "Maghnia"
}
]
},
{
"codeInterne": 64,
"clientName": "lkjhgf",
"clientPhone": "+213778217469",
"codeExterne": "dfghjk",
"email": "talcorpdz#gmail.com",
"clientType": 1,
"clientEtat": 1,
"identifiant": "lkjhgf",
"contacts": [
{
"nom": "Taleb",
"prenom": "Mohammed",
"telephonePortable": "02354649",
"email": "talcorpdz#gmail.com"
}
],
"adresses": [
{
"adress": "Batiments des enseignants Mohammed Khemist",
"ville": "Maghnia"
}
]
}
]
and here is the part where I do the post request
.
$(document).on('click', '#menu0-func1-menu0-func1', function(){
console.log(printData);
var settings = {
"async" : true,
"crossDomain" : true,
"url" : "http://"+document.location.host+"/facturation/print/client",
"method" : "POST",
"headers" : {
"cache-control" : "no-cache",
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
"processData" : false,
"contentType" : "application/json",
"dataType" : "json",
"data" : printData
}
$.ajax(settings).done(function(response) {
console.log(response);
});
});
the post is well received by my controller which is coded as the following :
#RestController
#RequestMapping(PrintController.API)
public class PrintController {
public static final String API="print";
#PostMapping("client")
public void export(#RequestBody List<ClientJsonDto> datas,HttpServletResponse response){
System.out.println(datas);
// processing the print mechanisme
}
}
finally here is my ClientJsonDto.java
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"codeInterne",
"clientName",
"clientPhone",
"codeExterne",
"email",
"clientType",
"clientEtat",
"identifiant",
"contacts",
"adresses"
})
public class ClientJsonDto {
#JsonProperty("codeInterne")
private Integer codeInterne;
#JsonProperty("clientName")
private String clientName;
#JsonProperty("clientPhone")
private String clientPhone;
#JsonProperty("codeExterne")
private String codeExterne;
#JsonProperty("email")
private String email;
#JsonProperty("clientType")
private Integer clientType;
#JsonProperty("clientEtat")
private Integer clientEtat;
#JsonProperty("identifiant")
private String identifiant;
#JsonProperty("contacts")
private List<Contact> contacts = null;
#JsonProperty("adresses")
private List<Adress> adresses = null;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
// getters, setters
}
adress.java
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"adress",
"ville"
})
public class Adress {
#JsonProperty("adress")
private String adress;
#JsonProperty("ville")
private String ville;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
//getters, setters
}
contact.java
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"nom",
"prenom",
"telephonePortable",
"email"
})
public class Contact {
#JsonProperty("nom")
private String nom;
#JsonProperty("prenom")
private String prenom;
#JsonProperty("telephonePortable")
private String telephonePortable;
#JsonProperty("email")
private String email;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
//getters setters
}
the exception that I m facing is:
2018-11-18 15:12:40.255 WARN 1768 --- [nio-8082-exec-9]
.w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP
message:
org.springframework.http.converter.HttpMessageNotReadableException:
JSON parse error: Unrecognized token 'object': was expecting ('true',
'false' or 'null'); nested exception is
com.fasterxml.jackson.core.JsonParseException: Unrecognized token
'object': was expecting ('true', 'false' or 'null') at [Source:
java.io.PushbackInputStream#1df244f9; line: 1, column: 9]
what can I do to see what my rest controller is receiving as request body before that jackson tries to marshal?
what can I do to fix this exception?
Your json value and mapping is all correct but i can't see producer and consumer with post mapping request as you have to explicitly define the producer and consumer.
The error could be due to the format of data you are giving to your controller. Your controller method is expecting JSON string. For example in case of jQuery, JSON.stringify() gives you JSON string. So I would suggest you confirm this at the client side from where you're sending the data to this controller.
Code which you need to change and check.
#RestController
#RequestMapping(PrintController.API)
public class PrintController {
public static final String API="print";
#PostMapping("client",produces=MediaType.APPLICATION_JSON_VALUE,consumes=MediaType.APPLICATION_JSON_VALUE)
public void export(#RequestBody List<ClientJsonDto> datas,HttpServletResponse response){
System.out.println(datas);
// processing the print mechanisme
}
}
I believe you want to see what is being received so that you can find why it is not getting mapped to your DTO.
Try changing
#RequestBody List<ClientJsonDto> datas
to
#RequestBody List<Map> datas
or
#RequestBody List datas
And see if you can print and debug it.
Finally got fixed
I based my fix upon this tutorial,what I mentioned is I m handling my array in a shady way so I tried the same principle, and I added the JSON.stringify and changed the datatype to text
here is all the changes that I made
$(document).on('click', '#menu0-func1-menu0-func1', function(){
console.log(printData);
var jsonData =JSON.parse(JSON.stringify(printData));
var settings = {
"async" : true,
"crossDomain" : true,
"url" : "http://"+document.location.host+"/facturation/print/client",
"method" : "POST",
"headers" : {
"cache-control" : "no-cache",
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
"processData" : false,
"contentType" : "application/json",
"dataType" : "text",
"data" : JSON.stringify(printData)
}
$.ajax(settings).done(function(response) {
console.log(response);
});
});
the print data that I m printing is handled as below
var printData =[];
function displayList(){
console.log("click");
if(console.log($('#search-client').val())){
console.log($('#search-client').val().toLowerCase());
}
var as=clientsData.filter((n,i,a) =>{return (
n.email.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.contacts[0].nom.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.contacts[0].prenom.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.adresses[0].ville.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.contacts[0].telephonePortable.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0)});
var html=' ';
console.log(as.length);
printData = [];
for(var i=0; i<as.length ; i++){
var ClientJsonDto = as[i];
html+=[{client : as[i] , index : i}].map(RefCliElement).join('');
printData.push(ClientJsonDto);
}
console.log(JSON.stringify(printData));
$('#clientList').html(html);
console.log(html);
}
before the fix it was like this, may be this idea is to avoid because I was using a jquery array of objects whithout knowing
var printData;
function displayList(){
console.log("click");
if(console.log($('#search-client').val())){
console.log($('#search-client').val().toLowerCase());
}
var as=clientsData.filter((n,i,a) =>{return (
n.email.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.contacts[0].nom.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.contacts[0].prenom.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.adresses[0].ville.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.contacts[0].telephonePortable.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0)});
var html=' ';
console.log(as.length);
for(var i=0; i<as.length ; i++){
html+=[{client : as[i] , index : i}].map(RefCliElement).join('');
}
printData = as;
$('#clientList').html(html);
console.log(html);
}
wish this helps entry level like me in the futur
Related
I'm implementing query layer on database by using GraphQl and spring boot project to perform CRUD operation on sql database. In GraphQL schema i mentioned some fields to be mandatory and when those fields are not mentioned in query it is returning ValidationError error message in default format with 200 status code.
Error :
{
"data": null,
"errors": [
{
value=StringValue{value='1235'}}]}}]}' is missing required fields '[book_type]' # 'create_book'",
"locations": [
{
"line": 3,
"column": 23,
"sourceName": null
}
],
"description": "argument 'insert' with value value=StringValue{value='1235'}}]}}]}' is missing required fields '[book_type]'",
"validationErrorType": "WrongType",
"queryPath": [
"create_book"
],
"errorType": "ValidationError",
"path": null,
"extensions": null
}
],
"dataPresent": false,
"extensions": null
}
And here is my code with layer architecture pattern
Controller :
#Autowired
private GraphQLServer graphQlServer;
#PostMapping("test")
public ResponseEntity<Object> graphQl(#RequestBody String body){
ExecutionResult response = graphQlServer.execute(body);
return ResponseEntity.ok(response);
}
Service :
#Service
public class GraphQLServer {
#Autowired
private GraphQL graphQl;
public ExecutionResult execute(String query) {
return graphQl.execute(query);
}
}
Config :
#Bean
public GraphQL loadSchema() throws IOException {
File schemaFile = schemaResource.getFile();
TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(schemaFile);
RuntimeWiring wiring = buildRuntimeWiring();
GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(typeRegistry, wiring);
return GraphQL.newGraphQL(schema).build();
}
private RuntimeWiring buildRuntimeWiring() {
return RuntimeWiring.newRuntimeWiring()
.type("Mutation", mutationWiring -> mutationWiring.dataFetcher("create_book", bookDataFetcher))
.build();
}
BookDataFetcher :
#Override
public Map<String, Object> get(DataFetchingEnvironment environment) {
//return data from db by getting Map properties from environment
}
The above code is working as expected but my question here is How to customize the error message? In the error message i would like to mention the status 400 since it is bad request from client
First of all , you should call toSpecification() on ExecutionResult to make sure the response obeys the GraphQL Specification.
By default , there is only one ExecutionResult 's implementation provided by graphql-java which is ExecutionResultImpl , so you can cast ExecutionResult to it in order to use its transform() to update its state.
ExecutionResultImpl internally contains all errors detected by the graphql-java. All of them are in the subclass of GraphQLError which mean you have to cast it to the specific sub-class during customization.
In your case , the subclass is ValidationError and the codes look something like :
#PostMapping("test")
public ResponseEntity<Object> graphQl(#RequestBody String body){
ExecutionResult response = graphQlServer.execute(body);
ExecutionResultImpl responseImpl = (ExecutionResultImpl) response;
List<GraphQLError> customizedErrors = Lists.newArrayList();
for (GraphQLError gqlError : responseImpl.getErrors()) {
//Do your error custmosation here....
GraphQLError customizedError = gqlError;
if (gqlError instanceof ValidationError) {
ValidationError error = (ValidationError) gqlError;
customizedError = new ValidationError(error.getValidationErrorType(), error.getLocations(),
"Customizing some error message blablabla....");
}
customizedErrors.add(customizedError);
}
Map<String, Object> specResponse = responseImpl.transform(b->b.errors(customizedErrors)).toSpecification();
return ResponseEntity.ok(specResponse);
}
I am trying to call REST service by passing object as parameter which contains list of other custom objects. I am getting "Error 405: Request method POST not supported" error.
Client side code-
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(SSLConnectionSocketFactory.getSystemSocketFactory()).build();
httpPost = new HttpPost("http://api100.abc.xyz.com:9080/abcd/api/sscws/v1/saveContributions");
httpPost.addHeader(WebAppConstants.CONTENT_TYPE, WebAppConstants.APPLICATION_JSON);
httpPost.addHeader(WebAppConstants.ACCEPT, WebAppConstants.APPLICATION_JSON);
httpPost.addHeader(WebAppConstants.X_USERNAME, userContext.getUserID());
httpPost.addHeader(WebAppConstants.X_ENTERPRISE_ID, "123456");
httpPost.addHeader(WebAppConstants.X_UNIQUE_ID, "A548742ATG"); //to do
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String requestParamJson = ow.writeValueAsString(contribRequestParamDto);
httpPost.setEntity(new StringEntity(contribRequestParamDto, WebAppConstants.UTF_8));
In above code contribRequestParamDto is a object of ContributionsRequestParamDto class which will look this-
public class ContributionsRequestParamDto {
private String tokenID;
private String taxID;
private String affiliateID;
private long planID;
private String accountNumber;
private String bankAccountNumber;
private String transitId;
private BigDecimal eftAmt;
private Date ppeDate;
private String taxYear;
private Short planType;
private List<ParticipantsDeferralDto> participantsDeferrals;
private List<EmployersContributionDto> employersContributions;
}
REST endpoint will look like this-
#Transactional
#RestController
#RequestMapping("/v1")
#Api(value="v1", description="")
public class SscRestController {
#RequestMapping(value="/saveContributions",
method=RequestMethod.POST, produces={MediaType.APPLICATION_JSON_VALUE}, consumes={MediaType.APPLICATION_JSON_VALUE})
#ApiOperation(value="Returns the saved contributions object")
public String saveContributions(#RequestBody ContributionsRequestParam contributionsParam) throws Exception {
return "success";
}
}
Json request body is-
{
"tokenID" : "123456789",
"taxID" : "123456",
"affiliateID" : "123456789",
"planID" : 123456,
"ppeDate" : "2017-10-24",
"taxYear" : "2017",
"planType" : 1,
"participantsDeferrals" : [ {
"taxId" : "555555",
"participantDeferralAmt" : 22.00
} ],
"employersContributions" : [ {
"taxId" : "555555",
"employerContributionAmt" : 22.00
} ]
}
This is not working as I am getting "Error 405: Request method POST not supported" error. It will work if remove list fields for 'participantsDeferrals' and 'employersContributions' from JSON request body by removing those list fields from 'ContributionsRequestParamDto' object. So I am sure that there is something wrong with list of custom objects and its corresponding JSON request body. Am I missing something here? Please help. Thanks!
I have changed the type of the Date. Now it is normal String and not SQL date. After changing its type to string in object, it is working fine
I am new for jersey, while i am trying to receive data from jquery to java using ajax it doesn't map pojo.
POJO :-
#XmlRootElement
public class RulesTO {
private int ruleId;
private String ruleName;
private int ruleStudioId;
private String ruleStudioName;
private String ruleDescription;
private Boolean ruleStatus;
private List<SitesTO> siteRule;
private List<IspsTO> ispRule;
private List<CountriesTO> countryRule;
private String studioDefaultRule;
//getters and setters
}
Ajax :-
var rulesTO = {
ruleName : $('#ruleName').val(),
ruleStudioId : $('#studios option:selected').attr("stream"),
ruleStudioName : $('#studios option:selected').text(),
ruleDescription : $('#ruledescription').val(),
ruleStatus : false,
siteRule : newSiteObject,
ispRule : newIspObject,
countryRule : newCountryObject,
studioDefaultRule : newStudioDefaultObject
}
$.ajax({
url : "/idns/idnsData/saveConfiguration",
type : "POST",
contentType : "application/json",
dataType : "json",
data : JSON.stringify(rulesTO),
success : function(data){
alert("success insert");
}
});
java:-
#Path("/idnsData")
public class IdnsDataHandler {
private static Logger logger = Logger.getLogger(IdnsDataHandler.class);
private Connection connection = null;
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#Path("/saveConfiguration")
public RulesTO saveConfiguration(RulesTO rulesTO) throws Exception{
try{
logger.info("IdnsDataHandler : saveConfiguration Method start");
System.out.println("Rule Id : "+rulesTO.getRuleId());
System.out.println("Rule Name : "+rulesTO.getRuleName());
System.out.println("Studio Id : "+rulesTO.getRuleStudioId());
System.out.println("Studio Name : "+rulesTO.getRuleStudioName());
System.out.println("Rule Description : "+rulesTO.getRuleDescription());
System.out.println("Rule Status : "+rulesTO.isRuleStatus());
System.out.println("List Site : "+rulesTO.getSiteRule().size());
System.out.println("List Isp : "+rulesTO.getIspRule().size());
System.out.println("List Country : "+rulesTO.getCountryRule().size());
System.out.println("List studioDefault : "+rulesTO.getStudioDefaultRule());
List<SitesTO> takeall = rulesTO.getSiteRule();
for(int i=0;i<takeall.size();i++){
System.out.println("===="+takeall.get(i).getSiteName());
}
}
}
output :-
Rule Id : 0
Rule Name : example
Studio Id : 3
Studio Name : MAsia
Rule Description : test
Rule Status : false
List Site : 5
List Isp : 0
List Country : 0
List studioDefault : null
but i want List site object and values map to the POJO, but does not work. please kindly help me, this is very useful for my project. thank you
check the dependencies for Moxy json, Thats work for me.
1.jersey-media-moxy-2.13.jar
2.jersey-entity-filtering-2.13.jar
3.org.eclipse.persistence.antlr-2.5.0.jar
4.org.eclipse.persistence.asm-2.5.0-RC2.jar
5.org.eclipse.persistence.core-2.5.0-RC2.jar
6.org.eclipse.persistence.moxy-2.5.0.jar
I have a JSON object like as follows:
[
{
"usernameid": [
"2",
"7"
],
"phaseid": [
"2",
"7"
],
"weekstartdate": "2014-11-02"
}
]
I try to map this JSON in a POJO in my controller:
public ModelAndView approveTimesheet(#RequestBody ApproveTimesheet timesheet,HttpSession session)
{
logger.info("yes");
}
My AJAX Call:
$.ajax({
type : 'post',
url : 'PendingTimesheet',
contentType : "application/json; charset=utf-8",
data : JSON.stringify(jsonObj),
success : function(data) {
},
});
POJO class:
public class ApproveTimesheet
{
private String[] usernameid;
private String[] phaseid;
private String weekstartdate;
//Getters and Setters
}
I am getting the below exception
out of START_ARRAY token
at [Source: org.apache.catalina.connector.CoyoteInputStream#7097326d; line: 1, column: 1]
How to correctly map the above JSON request in Spring controller?
Any Ideas will be greatly appreciated.
You are sending an array of JSON objects and not a singleton one.
Your controller signature should then hold a Collection or Array of ApproveTimesheet on front of the #RequestBody annotation. (I would suggest using arrays to avoid generic types mismatch):
public ModelAndView approveTimesheet(
#RequestBody ApproveTimesheet[] timesheets,
HttpSession session)
{
for(int i = 0; i < timesheets.length; i++)
{
logger.info(timesheets[i]);
}
//...
}
I am newbie in Spring. I generate the JSON like below:
[
{
"customer" : "16", "project" : "19",
"phase" : "47", "approver" : "5",
"date1" : "", "date2" : "",
"date3" : "", "date4" : "",
"date5" : "", "date6" : "",
"date7" : "", "activity" : "1"
},
{
"customer" : "17", "project" : "20",
"phase" : "48", "approver" : "3",
"date1" : "", "date2" : "",
"date3" : "", "date4" : "",
"date5" : "", "date6" : "",
"date7" : "", "activity" : "1"
}
]
I am passed this JSON to my Spring controller:
$.ajax({
type: 'post',
url: 'NewTimesheet',
dataType : 'json',
data: JSON.stringify(jsonObj),
success: function(data) {
console.log(data);
}
});
I am mapped the request to controller like below:
#RequestMapping(value="NewTimesheet", headers = { "Content-type=application/json" })
#ResponseBody
public String addNewTimesheet(#RequestBody List<Timesheet> timesheet,
HttpSession session) {
logger.info("timesheet list size is" + timesheet.size());
return "success";
}
Timesheet class:
public class Timesheet {
private String project;
private String phase;
private String approver;
private String customer;
private String date1;
private String date2;
private String date3;
private String date4;
private String date5;
private String date6;
private String date7;
private String activity;
//Getters and setters
}
But my request is not mapped with the conroller. My console displays like below:
WARN
org.springframework.web.servlet.PageNotFound.handleNoSuchRequestHandlingMethod:142
- No matching handler method found for servlet request: path '/NewTimesheet', method 'POST', parameters
map['[{"customer":"16","project":"19","phase":"47","approver":"5","date1":"","date2":"","date3":"","date4":"","date5":"","date6":"","date7":"","activity":"1"},{"customer":"17","project":"20","phase":"48","approver":"3","date1":"","date2":"","date3":"","date4":"","date5":"","date6":"","date7":"","activity":"1"}]'
-> array['']]
How to map my JSON to controller? Any help will be greatly appreciated!!!
You need to annotate the class as Controller, add a RequestMapping in your class and the HTTP method your calling in your method.
#Controller
#RequestMapping("/NewTimesheet")
public class MyClassName {
#RequestMapping(value={ "", "/" }, method = RequestMethod.POST, headers = { "Content-type=application/json" })
#ResponseBody
public String addNewTimesheet(#RequestBody List<Timesheet> timesheet,HttpSession session){
logger.info("timesheet list size is"+timesheet.size());
return "success";
}
}
Change #RequestBody to #ModelAttribute before the list in the controller. And in your json, put 'timesheet.' before every field, that is, timesheet.customer,timesheet.project.... such like that. That would work.
You need to define method=post. also I added produces = "application/json"
#RequestMapping(value="NewTimesheet", method = RequestMethod.POST, produces = "application/json")
#ResponseBody
public String addNewTimesheet(#RequestBody List<Timesheet> timesheet,HttpSession session){
logger.info("timesheet list size is"+timesheet.size());
return "success";
}
A couple things that might be causing problems for you:
Make sure you have all of the necessary dependencies for Jackson. For Maven, this would be:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.2</version>
</dependency>
You don't need to stringify your JavaScript object, this is done implicitly. You should also name your submitted variable, since it must map to the domain object:
$.ajax({
method : 'post',
url : 'NewTimesheet',
dataType : 'json',
data:{ 'timesheet': jsonObj },
success : function(data) {
console.log(data);
}
});
Your controller should be configured to explicitly handle a POST request. Setting the accepted content type in the headers is not necessary. Also, I believe you need to map your domain objects to an array and not a list:
#RequestMapping(value="NewTimesheet", method = RequestMethod.POST)
public #ResponseBody String addNewTimesheet(#RequestParam("timesheet") Timesheet[] timesheet,HttpSession session){
logger.info("timesheet list size is"+timesheet.length);
return "success";
}
If you are using a relatively recent version of Spring MVC, there is no additional configuration required to handle requests for and producing JSON. Your AJAX request specifies a JSON response, which Spring will recognize and delegate to Jackson for serializing the input and output.
In my ajax request i added the contentType:application/json.After adding this controller mapped my ajax request.Thanks for all.