I have the following API-method:
#PatchMapping("/{id}")
public ResponseEntity<?> partialProjectUpdate(#PathVariable long id, #RequestBody EntryStatus status) throws DailyEntryNotFoundException {
return dailyEntryService.partialDailyEntryUpdate(id, status);
}
EntryStatus is an enum:
public enum EntryStatus {
OPEN,
PROGRESS,
CHECKED,
BOOKED,
UNAVAILABLE;
private static Map<String, EntryStatus> namesMap = new HashMap<String, EntryStatus>(3);
static {
namesMap.put("OPEN", OPEN);
namesMap.put("PROGRESS", PROGRESS);
namesMap.put("CHECKED", CHECKED);
namesMap.put("BOOKED", BOOKED);
namesMap.put("UNAVAILABLE", UNAVAILABLE);
}
#JsonCreator
public static EntryStatus forValue(String value) {
return namesMap.get(value);
}
#JsonValue
public String toValue() {
for (Map.Entry<String, EntryStatus> entry : namesMap.entrySet()) {
if (entry.getValue() == this)
return entry.getKey();
}
return null; // or fail
}
}
I call the method in typescript like this:
partialUpdateDailyEntry(dailyEntry: DailyEntry, status): Observable<any> {
const statusName: string = status.name;
return this.http.patch(BASE_URL + dailyEntry.id, statusName, this.authService.setHeaders('application/json'))
.pipe(
catchError(this.handleService.error)
);
}
statusName is a string, but the problem is that its getting sent without quotemarks via JSON. The RequestBody is for example OPEN instead of "OPEN" which gives me the following error:
JSON parse error: Unrecognized token 'OPEN': was expecting ('true', 'false' or 'null').
As stated thats caused by the fact that the string is sent without quotemarks.
I could fix that problem by adding the quotemarks manually to statusName like this:
const statusName: string = '"' + status.name + '"';
But that cant be the proper solution, is there a better way to do it?
Try with
#JsonFormat(shape = JsonFormat.Shape.STRING)
public enum EntryStatus{
OPEN,
PROGRESS,
CHECKED,
BOOKED,
UNAVAILABLE;
}
maybe you could put
namesMap.put("OPEN", OPEN);
as
namesMap.put("\"OPEN\"", OPEN);
You are adding the header that you are sending JSON, but "OPEN" is not a valid JSON value.
You should either change your headers:
this.authService.setHeaders('text/plain')
Or change how you send it:
this.http.patch(BASE_URL + dailyEntry.id, { status: statusName});
And change your java backend to handle to receive the object and read the status
Or stringify it before sending it:
const statusName: string = JSON.stringify(status.name);
Related
I'm trying to create an authenticated websocket to wss://ws-feed-public.sandbox.exchange.coinbase.com and need to create a "signature" for my requests using the following:
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
public class Signature {
private final String secretKey;
public Signature(final String secretKey) {
this.secretKey = secretKey;
}
public String generate(String requestPath, String method, String body, String timestamp) {
String message = timestamp + method.toUpperCase() + requestPath + body;
return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, secretKey).hmacHex(message);
}
}
For this particular signature, requestPath is always a blank string, and method is always GET
I continuously get the following return:
{
"type":"error",
"message":"Authentication Failed",
"reason":"{\"message\":\"invalid signature\"}"
}
I have also tried utilizing Signature.java from Gdax-java https://github.com/irufus/gdax-java/blob/master/security/src/main/java/com/coinbase/exchange/security/Signature.java#L34 but to no avail.
What am I doing incorrectly? Any help is appreciated.
Update: I also tried setting requestPath to /users/self/verify.
I need to set different HTTP Status code for my REST webservice request.
Basically user will send ISBN number , I need to validate it
if user send empty request body , give error message ISBN cannot be empty
and set http status code
if user gives Alphabets , Given error message Alphabets not allowed and set http status code appropriate
if user gives wrong format, Give error message wrong format and set different HTTP status code.
if isbn is not valid, Give error message Not a Valid ISBN number and set appropriate HTTP status code.
If Valid ISBN number then return book name with http status as 200.
I tried setting http status code but its not reflecting.
#RequestMapping(value = "/person", method = RequestMethod.POST,
consumes = "application/json", produces = "application/json")
public ResponseEntity<StatusBean> findBook(#RequestBody String json) {
StatusBean sb = new StatusBean();
if(json==null) {
sb.setMessage("Request Cannot be Null");
return new ResponseEntity<StatusBean>(sb,HttpStatus.BAD_REQUEST);
}
if(!isNumeric(json)) {
sb.setMessage("Request Cannot have Alphabets Characters");
//here i need to set different status
return new ResponseEntity<StatusBean>(sb,HttpStatus.BAD_REQUEST);
}
if(!isValidFormat(json)) {
sb.setMessage("Request Cannot have Alphabets Characters");
//here i need to set different status
return new ResponseEntity<StatusBean>(sb,HttpStatus.BAD_REQUEST);
}
if(!isValidISBN(json)) {
sb.setMessage("Request Cannot have Alphabets Characters");
//here i need to set different status
return new ResponseEntity<StatusBean>(sb,HttpStatus.BAD_REQUEST);
}
Map<String,String> map = new HashMap<>();
map.put("book", "Effective Java");
sb.setResponseJSONMap(map);
return new ResponseEntity<StatusBean>(sb,HttpStatus.OK);
}
public class StatusBean {
private String message;
private Map<String,String> responseJSONMap;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Map<String, String> getResponseJSONMap() {
return responseJSONMap;
}
public void setResponseJSONMap(Map<String, String> responseJSONMap) {
this.responseJSONMap = responseJSONMap;
}
}
One of the most elegant solutions is the following:
You can throw a custom exception in case of a validation error, like this:
#RequestMapping(...)
public ResponseEntity<StatusBean> findBook(#RequestBody String json) throws Exception {
...
if(json==null) {
throw new NullRequestException();
}
if(!isNumeric(json)) {
throw new RequestContainsAlphabetsException();
}
if(!isValidFormat(json)) {
throw new InvalidFormatException();
}
...
}
And then you need to define an own, global exception handler at application level. In this custom exception handler, you will catch the thrown exceptions and send back a proper response to clients with a custom error message, an HTTP response code, a timestamp, etc.
For more details see this page.
#RequestMapping(value = "/person", method = RequestMethod.POST,
consumes = "application/json", produces = "application/json")
public ResponseEntity<StatusBean> findBook(#RequestBody(required=false) String json) {
// rest of the code
}
try using (required=false) with request body. Spring requires resuest body by default.
I need to return something into Response class format but I have an SAMLResult variable so when I get the Status (ResponseStatus) I don't find any way to parse it to a Responsevariable.
Has someone any idea how to do this ?
If i understand your problem correctly, you are only interested in the numeric SAMLResponse status and need to return this as a new value of type Response.
So you can simply build a new Response with the SAMLResponse status value:
int samlStatus = SAMLResponse.ResponseStatus;
Response response = Response.status(samlStatus).build();
return response;
Or you can intantiate a new Response object (by implementing all methods from the abstract Response class e.g. with default values) and set the SAMLResponse.ResponseStatus value in the getStatus() method. For example:
Response response = new Response() {
#Override
public int getStatus() {
int samlStatus = SAMLResult.ResponseStatus;
return samlStatus;
}
// override all other Response methods ...
}
return response;
In my REST application I have a #POST method which consumes x-www-form-urlencoded and produces application/json and is designed to create new appointments for a beauty center:
#POST
#Produces("application/json")
#Consumes("application/x-www-form-urlencoded")
public Response bookAppointment(#FormParam("date") Date appDate,
#FormParam("time") Time appTime, #FormParam("type") String appType,
#FormParam("clientName") String clientName, #FormParam("email") String clientEmail,
#DefaultValue("") #FormParam("message") String clientMsg) {
//externalize the validation of all fields to concentrate on "positive"
//scenario only
validator(appDate, appType, clientName, clientEmail);
Appointment appointment = build(appDate, appTime, appType,clientName,
clientEmail, clientMsg);
try {
repository.add(appointment);
return Response.ok(appointment).build();
} catch (Exception e) {
throw new InternalServerErrorException("Something happened in the application "
+ "and this apointment could not get saved. Please contact us "
+ "to inform us of this issue.");
}
}
As you may see for two Endpoint method attributes are Java objects (sql.Time and sql.Date). To convert them from strings coming from the client I am using ParamConverterProviders as taught in B. Burke's Restful Java with JAX-RS (p. 70-71) and this Stack Overflow question.
I am using Postman chrome add-on to send requests and everything works fine and dandy if for time and date I am sending the full String required attributes for valueOf() builder methods of sql.Date and sql.Time(i.e. yyyy-MM-dd and hh:MM:ss, respectively). However when I am sending time without seconds I receive the 404 Exception with a generic message.
This is what I am sending from Postman:
If you will take a look at one of the ParamConverterProviders you will see that I am accounting for partial user input and in either way am throwing a custom message for BadRequestException (which works for other validation constraints):
#Provider
public class SqlTimeConverterProvider implements ParamConverterProvider {
#Override
public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
System.out.println("SqlTimeConverterProvider");
if (rawType.equals(Time.class)) {
return new ParamConverter<T>() {
#Override
public T fromString(String value) {
//in case the ParamConverter does not do URI deconding
value = value.replaceAll("%3A", ":");
if (value.length() < 6) {
value = value.concat(":00");
}
if (!value.matches("([01]?[0-9]|2[0-3]):[0-5][0-9]"
+ "(:[0-5][0-9])*")) {
throw new BadRequestException(value + " is not an accepted Time format "
+ "please use this pattern: hh:mm:SS");
}
return rawType.cast(Time.valueOf(value));
}
#Override
public String toString(T value) {
Time timeRepr = (Time) value;
if (timeRepr.toLocalTime().getMinute() < 10) {
String reply = timeRepr.toLocalTime().getHour()+":"
+timeRepr.toLocalTime().getMinute();
return reply.concat("0");
}
return timeRepr.toLocalTime().toString();
}
};
}
return null;
}
}
Interesting enough using NetBeans debugger I have discovered that after this line in the code above:
System.out.println("SqlTimeConverterProvider");
if (rawType.equals(Time.class)) {
the 'Step over' moves the break-point to return null and the same thing repeats for the Date converter provider. As I am following meticulously the example from the book I am unsure as to why is the rawType being evaluated to false
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)