this my is rest request that is compatible for another service :
{
"fromDate": 1562773101000,
"toDate": 1563118701000,
"turnOverType": 4,
"fromAmount": 1,
"toAmount": 10000000,
"voucherDescription": null,
"articleDescription": null,
"referenceNumbers": [],
"offset": 3,
"pageSize": 20,
"iban": "BLAHBLAHBLAHBLAH"
}
and this is corresponding model that not match request :
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "TransferRequestInquiryFilter")
public class TransferRequestInquiryFilter implements Serializable {
#XmlElement(name = "sourceIbans")
private List<String> sourceIbans;
#XmlElement(name = "transferType")
private TransferType transferType;
#XmlElement(name = "fromTransferDate")
private Timestamp fromTransferDate;
#XmlElement(name = "toTransferDate")
private Timestamp toTransferDate;
#XmlElement(name = "fromRegistrationDate")
private Timestamp fromRegistrationDate;
#XmlElement(name = "toRegistrationDate")
private Timestamp toRegistrationDate;
#XmlElement(name = "trackingNumbers")
private List<String> trackingNumbers;
#XmlElement(name = "referenceNumbers")
private List<String> referenceNumbers;
#XmlElement(name = "transactionIds")
private List<String> transactionIds;
#XmlElement(name = "status")
private TransactionStatus status;
#XmlElement(name = "fromAmount")
private Long fromAmount;
#XmlElement(name = "toAmount")
private Long toAmount;
#XmlElement(name = "destinationIbans")
private List<String> destinationIbans;
and this is my controller ..
#RequestMapping(value = "/inquiry", method = RequestMethod.POST)
public #ResponseBody
ResponseEntity<List<ExtendedTransferRequest>> transferInquiry(#RequestBody #Valid TransferRequestInquiryFilter transferRequestInquiryFilter
, BindingResult bindingResult) {
// when validation not works return bad request
List<ErrorObject> errorObjects = requestInquiryValidator.validate(transferRequestInquiryFilter);
if (errorObjects.size() > 0) {
// just throw bad request and not detail of them
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
List<ExtendedTransferRequest> extendedTransferRequestList = new ArrayList<>();
ExtendedTransferRequest extendedTransferRequest = new ExtendedTransferRequest();
List<SettlementTransaction> settlementTransactionList = settlementSearch.findSettlement(transferRequestInquiryFilter);
extendedTransferRequestList = TransferInquiryResponseMapper.INSTANCE.SettlementTransactionInquiryResponse(setlementTransactionList);
return new ResponseEntity<>(extendedTransferRequestList, HttpStatus.OK);
}
just fromAmount and toAmount fills. but i want to get an exception for this situation and throw a bad request for client. how can i do that? If I get name conflict or type conflict between rest request and model , I need to handle it and riase a bad request for client. i am using spring mvc 5 and jackson-core and jackson-databind 2.9.4
Using validation-api, annotate proper validation for fields and #validated before controller method and using #valid before RequestBody object would throw proper validation exception.
Related
I have tried all the answer I have found on internet and nothing seems to be working.
I have added hibernate-validation, spring validation but both are not working and bindingResult.haserrors() is always false.
Dependencies I am using currently in my project
javax.validation:validation-api:2.0.1.Final
org.hibernate.validator:hibernate-validator:6.0.18.Final
org.springframework.boot:spring-boot-starter-validation:2.1.13.RELEASE
com.github.java-json-tools:json-schema-validator:2.2.8
io.springfox:springfox-bean-validators:2.9.2
Controller
public String processRequest(
#ApiParam(value = "Input JSON",
required = true) #Valid #RequestBody MyClass myClass,
BindingResult results) {
if (results.hasErrors()) {
List<FieldError> fieldErrors = results.getFieldErrors();
throw new InvalidFieldException(fieldErrors);
}
}
MyClass
public class MyClass {
#NotBlank
#Size(min = 1, max = 80)
private String firstName;
#Size(max = 80)
private String middleName;
#NotBlank
#Size(min = 1, max = 80)
private String lastName;
}
I am call controller using this myClass Object
MyClass myClass =
MyClass.builder().firstName("linus").lastName("").build();
Can someone please help me?
In my current implementation Validation for the two fields of SpecialTransactionDTO (transactionMetric and transactionRank) works in all cases. Now its parent class TransactionDTO that I receive as a #RequestBody contains a boolean field shouldValidate that indicates whether to validate the two fields of SpecialTransactionDTO or not.
How should I configure (turn off) validation for the cases when the value of shouldValidate flag is false?
#PostMapping("{id}/transaction/")
#ApiOperation(value = "Create transaction", httpMethod = "POST", response = TransactionDTO.class)
public ResponseEntity<Object> createTransaction(#PathVariable("id") Long accountId,
#Validated({TransactionNumber.class})
#RequestBody TransactionDTO transaction)
throws NotFoundException, URISyntaxException {
TransactionDTO result = transactionService.createTransaction(accountId, transaction);
return ResponseEntity.created(new URI("api/userAccount/" + accountId)).body(result);
}
#JsonSubTypes({
#JsonSubTypes.Type(value = SpecialTransactionDTO.class, name = SpecialTransactionDTO.TYPE),
#JsonSubTypes.Type(value = TransactionDTO.class, name = TransactionDTO.TYPE)
})
public class TransactionDTO {
#NotNull
private Long id;
#NotNull
private String transactionInitiator;
private Boolean shouldValidate;
private String transactionCode;
}
public class SpecialTransactionDTO extends TransactionDTO {
#NotNull
private Long userId;
#Pattern(regexp = "0|\\d{8,11}")
private String transactionMetric;
#Pattern(regexp = "\\d{1,3}")
private String transactionRank;
}
You could eliminate #Validated annotation altogether and imitate Spring's behaviour as follows:
#PostMapping("{id}/transaction/")
#ApiOperation(value = "Create transaction", httpMethod = "POST", response = TransactionDTO.class)
public ResponseEntity<Object> createTransaction(#PathVariable("id") Long accountId,
#RequestBody TransactionDTO transaction)
throws NotFoundException, URISyntaxException, MethodArgumentNotValidException {
// Check if we should validate here. Spring will convert your MethodArgumentNotValidException into HTTP 400
if(transaction.shouldValidate) {
SpringValidatorAdapter adapter = new SpringValidatorAdapter(validator);
BeanPropertyBindingResult result = new BeanPropertyBindingResult(transaction, transaction.getClass().getName());
adapter.validate(transaction, result, TransactionNumber.class);
if (result.hasErrors()) {
throw new MethodArgumentNotValidException(null, result);
}
}
TransactionDTO result = transactionService.createTransaction(accountId, transaction);
return ResponseEntity.created(new URI("api/userAccount/" + accountId)).body(result);
}
Im trying to hit Spring REST endpoint in my other module of the application. So im trying to use the REST Template to get a list of users as below :
The API request using REST Template :
public List<LeadUser> getUsersBySignUpType(String type, String id) {
String adminApiUrl = adminApiBaseUrl+"/crm/v1/users/?type="+type+"&id="+id;
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON);
HttpEntity entity = new HttpEntity(headers);
ResponseEntity<LeadUserList> response = restTemplate.exchange(
adminApiUrl, HttpMethod.GET, entity, LeadUserList.class);
return response.getBody().getUsersList();
}
LeadUserList class :
public class LeadUserList {
private List<LeadUser> usersList;
public List<LeadUser> getUsersList() {
return usersList;
}
}
LeadUser model class :
public class LeadUser {
#JsonProperty("id")
private String id;
#JsonProperty("email")
private String email;
#JsonProperty("name")
private String name;
#JsonProperty("businessName")
private String businessName;
#JsonProperty("phone")
private String phone;
#JsonProperty("address")
private String address;
#JsonProperty("createdTime")
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private Date createdTime;
#JsonProperty("updatedTime")
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private Date updatedTime;
#JsonProperty("bookletSignups")
private BookletSignUp bookletSignUp;
#JsonProperty("eventSignups")
private EventSignUp eventSignUp;
#JsonProperty("infoSignups")
private InfoSignUp infoSignUp;
#JsonProperty("webinarSignups")
private WebinarSignUp webinarSignUp;
public LeadUser() {
}
}
The API endpoint controller class :
#Controller
#Component
#RequestMapping(path = "/crm/v1")
public class UserController {
#Autowired
UserService userService;
#RequestMapping(value = "/users", method = GET,produces = "application/json")
#ResponseBody
public ResponseEntity<List<User>> getPartnersByDate(#RequestParam("type") String type,
#RequestParam("id") String id) throws ParseException {
List<User> usersList = userService.getUsersByType(type);
return new ResponseEntity<List<User>>(usersList, HttpStatus.OK);
}
}
Although the return type is JSON from the API endpoint im getting the above exception. What have I done wrong here?
The exception :
Could not extract response: no suitable HttpMessageConverter found for response type [class admin.client.domain.LeadUserList] and content type [application/json]
Try additional settings as follows,
httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
Also fix your exchange call,
ResponseEntity<List<LeadUser>> response = restTemplate.exchange(
adminApiUrl, HttpMethod.GET, entity, new ParameterizedTypeReference<List<LeadUser>>(){});
I use Angular 5 + Spring Boot. The problem is that I can not send information to my rest controller by post method.
I do not get any error either from the client side or from the server side.
Below the code you will see that I make get method which works correctly.
Let me apologize for my Еnglish.
Spring Entity { Dish }
#Entity
#Table(name = "DISHES")
#Data
public class Dish implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
#Column(name = "NAME", unique = true)
#NotNull(message = "Ястието трябва да има име.")
#Size(min = 3, max = 30, message = "Името на ястието трябва да е между 3 и 30 символа.")
private String name;
#Column(name = "DESCRIPTION")
#NotNull(message = "Описанието на ястието не може да е празно.")
#Size(min = 3, max = 300, message = "Описанието на ястието трябва да е между 3 и 30 символа.")
private String description;
#JsonIgnore
#OneToMany(cascade = CascadeType.ALL ,mappedBy = "dish")
#JsonBackReference
private List<DishCounter> dishCounters;
}
Angular Entity {Dish}
export class Dish {
constructor(public id?: number, public name?: string, public description?: string) {
}
}
Spring Rest Controller {Dish}
#CrossOrigin(origins = "http://localhost:4200")
#RestController
#RequestMapping("/dish")
public class DishRestController {
private static final Logger logger = LoggerFactory.getLogger(DishRestController.class);
private final DishService dishService;
#Autowired
public DishRestController(final DishService dishService) {
this.dishService = dishService;
}
#GetMapping("/all")
public ResponseEntity<List<Dish>> getAllDishes() {
logger.info("Rest controller find all dishes");
List<Dish> dishes = dishService.getAllDishes();
return ResponseEntity.status(HttpStatus.OK).body(dishes);
}
#PostMapping("/save")
public ResponseEntity<Void> saveDish(#RequestBody Dish dish) {
dishService.saveDish(dish);
return new ResponseEntity<>(HttpStatus.OK);
}
}
And Angular post Method
save(dish: Dish): Observable<Dish> {
let result: Observable<Dish>;
result = this.http.post(this.saveDishUrl, dish)
.map((resp => {
console.log(resp);
return resp;
}))
.catch(e => {
console.log(e);
return Observable.throw(e);
});
console.log(result);
return result;
}
Where are you calling subscribe on the post function? I don't see it here. As http post returns an observable, you must subscribe to it to make the call.
http.post(....).subscribe(response => <DO SOMETHING WITH IT>);
This might not be all of the errors on your code but this is something I noticed.
Your Java #PostMapping doesn't specify what it should be expected to receive and what it should produce in return.
#PostMapping(value = "save", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
For Angular 5, you're using Angular 4 service Syntax, I thought they changed that on 5.
I'm having trouble getting Jackson to correctly deserialize json into an object when calling a service (specifically we're using Jackson's ability to use JAXB annotations since we also want the service to use XML). I'm using Spring MVC and I'm using the RestTemplate class to make calls to the service.
Here is where I setup the MappingJacksonHttpMessageConverter for my junit:
ObjectMapper jsonMapper = new ObjectMapper();
AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
jsonMapper.getDeserializationConfig().setAnnotationIntrospector(introspector);
jsonMapper.getSerializationConfig().setAnnotationIntrospector(introspector);
jsonMapper.getSerializationConfig().setSerializationInclusion(Inclusion.NON_NULL);
MappingJacksonHttpMessageConverter jacksonConverter = new MappingJacksonHttpMessageConverter();
jacksonConverter.setObjectMapper(jsonMapper);
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(jacksonConverter);
template.setMessageConverters(converters);
And I call the service like so:
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Accept", "application/json");
HttpEntity<String> requestEntity = new HttpEntity<String>(requestHeaders);
ResponseEntity<NamedSystem> responseEntity = template.exchange(baseURL + "/{NamedSystemId}",
HttpMethod.GET, requestEntity, NamedSystem.class, orgId1);
My NamedSystem class is set up like so:
#XmlRootElement(name = "NamedSystem", namespace = "http://schemas.abc.workplace.com/NamedSystem")
public class NamedSystem {
private String id;
private String name;
private String description;
private Set<NamedSystemAlias> aliases;
private String href;
#XmlAttribute(required = false, name = "id")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#XmlAttribute(required = false, name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlAttribute(required = false, name = "description")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#XmlElementWrapper(required = false, name = "aliases", namespace = "http://schemas.abc.workplace.com/NamedSystem")
#XmlElement(required = false, name = "alias", namespace = "http://schemas.abc.workplace.com/NamedSystem")
public Set<NamedSystemAlias> getAliases() {
return aliases;
}
public void setAliases(Set<NamedSystemAlias> aliases) {
this.aliases = aliases;
}
#XmlAttribute(required = true, name = "href")
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
}
This is the error that results:
org.springframework.web.client.ResourceAccessException: I/O error: Unrecognized field "NamedSystem" (Class com.workplace.abc.named.NamedSystem), not marked as ignorable
at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream#c1429c; line: 1, column: 2]; nested exception is org.codehaus.jackson.map.JsonMappingException: Unrecognized field "NamedSystem" (Class com.workplace.abc.named.NamedSystem), not marked as ignorable
at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream#c1429c; line: 1, column: 2]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:453)
....
Caused by: org.codehaus.jackson.map.JsonMappingException: Unrecognized field "NamedSystem" (Class com.workplace.abc.named.NamedSystem), not marked as ignorable
at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream#c1429c; line: 1, column: 2]
at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:159)
at org.codehaus.jackson.map.deser.StdDeserializationContext.unknownFieldException(StdDeserializationContext.java:247)
at org.codehaus.jackson.map.deser.StdDeserializer.reportUnknownProperty(StdDeserializer.java:366)
at org.codehaus.jackson.map.deser.StdDeserializer.handleUnknownProperty(StdDeserializer.java:352)
at org.codehaus.jackson.map.deser.BeanDeserializer.handleUnknownProperty(BeanDeserializer.java:543)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:402)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:287)
at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:1588)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1172)
at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:132)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:154)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:74)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:619)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:446)
... 32 more
It seems it doesn't recognize the rootElement 'NamedSystem' to be able to deserialize. How would I get it to do that? I've seen examples that use the same JAXB annotations and they work fine so I'm not sure what's different about my case or how I might force it to correctly deserialize it. If anyone can offer any help, I'd appreciate it.
If anyone comes along this kind of problem, this might fix it for you: Enable Jackson to not output the class name when serializing (using Spring MVC)
See my answer and follow the link for an example.