I'm currently sending a GET request which is returning a null body in the response.
#Service
public class CarService {
private RestTemplate restTemplate;
private final String url = "url";
private final String accessToken = "x";
#Autowired
public CarService () throws URISyntaxException {
restTemplate = new RestTemplate();
}
public void fetchCars() throws URISyntaxException {
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
ResponseEntity<CarList> carList = restTemplate.exchange
(RequestEntity.get(new URI(url)).headers(headers).build(), CarList.class);
}
}
The CarList.class looks like this:
#JsonIgnoreProperties(ignoreUnknown = true)
public class CarList{
private List<Car> carList;
public CarList(List<Car> carList) {
this.carList= carList;
}
public CarList() {
}
public List<Car> getCarList() {
return carList;
}
#Override
public String toString() {
return "CarList{" +
"carList=" + carList +
'}';
}
}
The response in Postman looks like this:
{
"cars": [
{
"carUid": "aaaa-ccc-dd-cc-ee",
"model": "hyundai",
"price": 20000,
"soldAt": "2021-09-24T22:10:15.307Z"
}
]
}
Am I missing something?
It's the first time I try to consume from a client, so take in consideration the most basic things that I might be missing.
I've already tested the GET request in Postman with the given accessToken and it's working fine.
You carList object is private, try providing a setter method for this object and if the contract is fine, the deserialization will work fine.
#JsonIgnoreProperties(ignoreUnknown = true)
public class CarList{
private List<Car> carList;
public CarList(List<Car> carList) {
this.carList= carList;
}
public CarList() {
}
public List<Car> getCarList() {
return carList;
}
public setCarList(List<Car> carList) {
this.carList= carList;
}
#Override
public String toString() {
return "CarList{" +
"carList=" + carList +
'}';
}
}
Related
I am working on passing the list of from and to dates in the rest url.
For eg :
public ResponseEntity<String> periodData(
#RequestHeader(value = "Authorization") String authorization,
#PathVariable("partyGroupId") String partyGroupId,
#RequestBody DateRangeModel dateRangeModel){
return response;
}
Here is my DateRangeModel :
public class DateRangeModel {
#JsonProperty
private List<DateRange> dateRanges;
public List<DateRange> getDateRanges() {
return dateRanges;
}
public void setDateRanges(List<DateRange> dateRanges) {
this.dateRanges = dateRanges;
}
}
RequestBody :
{
"dateRanges": [
{
"fromDate": "2018-10-26",
"toDate": "2018-10-29"
},
{
"fromDate": "2018-10-21",
"toDate": "2018-10-20"
}
]
}
Could you please guide me how to pass these parameters in postman?
Thanks in advance!
Can you just add two dates like fromDate and toDate
public ResponseEntity<String> periodData(
#RequestHeader(value = "Authorization") String authorization,
#PathVariable("partyGroupId") String partyGroupId,
#PathVariable("fromDate") String fromDate,#PathVariable("toDate") String toDate){
return response;
}
I think a #PathVariable isn't suitable for this purpose then. #PathVariable means that the parameter is a part of the URL. Lets say there is a #PathVariable("id") and a #RequestMapping(value = "/groups/{id}"). Then the id's value will be passed as a parameter {id}. In you case the best way to achive a result is to create some Model class and add into it a list of DateRange as a property:
I've just modeled the case and it works fine for me:
public class DateRange {
private Date fromDate;
private Date toDate;
public Date getFromDate() {
return fromDate;
}
public void setFromDate(Date fromDate) {
this.fromDate = fromDate;
}
public Date getToDate() {
return toDate;
}
public void setToDate(Date toDate) {
this.toDate = toDate;
}
}
public class DateRangeModel {
#JsonProperty
private List<DateRange> dateRanges;
public List<DateRange> getDateRanges() {
return dateRanges;
}
public void setDateRanges(List<DateRange> dateRanges) {
this.dateRanges = dateRanges;
}
public DateRangeModel() {
}
}
#RequestMapping(
value = "/testapi/test", method = RequestMethod.PUT,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public #ResponseBody DateRangeModel test(
#RequestBody DateRangeModel data,
HttpServletRequest request) {
return data;
}
Request body:
{
"dateRanges": [
{
"fromDate": "2018-10-26",
"toDate": "2018-10-29"
},
{
"fromDate": "2018-10-21",
"toDate": "2018-10-20"
}
]
}
Response:
{
"dateRanges": [
{
"fromDate": 1540501200000,
"toDate": 1540760400000
},
{
"fromDate": 1540069200000,
"toDate": 1539982800000
}
]
}
Of course the problem of dates deserialization is out of the scene
I have below class referencing to itself:
#Entity
#Inheritance(strategy = TABLE_PER_CLASS)
//#JsonIdentityInfo(property="rowId", generator = ObjectIdGenerators.PropertyGenerator.class)
public abstract class AbstractEntity implements Serializable {
/**
*
*/
private static final long serialVersionUID = 568799551343430329L;
#OneToOne(optional=false, fetch=FetchType.EAGER)
#JoinColumn(name="createdBy")
protected User createdBy;
#OneToOne(optional=false, fetch=FetchType.EAGER)
#JoinColumn(name="lastUpdatedBy")
protected User lastUpdatedBy;
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(unique = true, nullable = false, updatable = false, length = 7)
private Integer rowId;
public User getCreatedBy() {
return this.createdBy;
}
public void setCreatedBy(User createdBy) {
this.createdBy = createdBy;
}
public User getLastUpdatedBy() {
return this.lastUpdatedBy;
}
public void setLastUpdatedBy(User lastUpdatedBy) {
this.lastUpdatedBy = lastUpdatedBy;
}
public Integer getRowId() {
return this.rowId;
}
public void setRowId(Integer RowId) {
this.rowId = RowId;
}
public String toString() {
return "[Id]:" + this.rowId + " - [CreatedBy]:" + this.createdBy;
}
}
Then I have a class User extending this class and a RepositoryUser interface:
public interface RepositoryUser extends CrudRepository<User, Integer> {
}
And a Controller:
#Controller
#RequestMapping(path = "/user")
public class ServiceUser {
#Autowired
private RepositoryUser repositoryUser;
#GetMapping(path="/all", produces = "application/json; charset=UTF-8", headers = "Accept=application/json")
public #ResponseBody Iterable<User> getAllUsers() {
return repositoryUser.findAll();
}
#PostMapping(path="/add", consumes="application/json")
public #ResponseBody User createOneUser(#RequestBody User user) {
System.out.println(user);
return repositoryUser.save(user);
}
}
My issue is that I'm making reference to User twice (createdby and lastupdatedby) in the same class and either I tried JSonIdentityInfo, Jsonmanaged,jsonback nothing works. correctly.
I need to be able to have
{
User 1 data including created by and last updated by
User 2 data including created by and last updated by
}
and when I add I need to set the user who creates the record.
Can you please help me ?
Thanks a lot!
You could write/try a Custom Serializer Using StdSerializer.
Example of CustomJsonSerializer. NB: Did not run the code.
public class CustomJsonSerializer extends StdSerializer<AbstractEntity> {
public CustomJsonSerializer() {
this(null);
}
public CustomJsonSerializer(Class<AbstractEntity> t) {
super(t);
}
#Override
public void serialize(AbstractEntity value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
Field[] fields = value.getClass().getDeclaredFields();
jgen.writeStartObject();
for (Field field : fields) {
field.setAccessible(true);
try {
// Do the proper field mapping for field types . Object type example
jgen.writeObjectField(field.getName(), field.get(value));
} catch (Exception e) {
// catch error
}
}
jgen.writeEndObject();
}
}
Then on your Rest Method use #JsonSerialize
#JsonSerialize(using = CustomJsonSerializer.class)
#GetMapping(path="/all", produces = "application/json; charset=UTF-8", headers = "Accept=application/json")
public #ResponseBody Iterable<User> getAllUsers() {
return repositoryUser.findAll();
}
Please see Custom Serializer And StdSerializer
Possible different solution
jackson-bidirectional infinite-recursion
JSON Request:
{
"notificationType" : "ISSUER_OTP1ee2asasa",
"content" : "hi fff this is fff template content for SBI email good and mobile dfdfdfd and remaining balance is 333 and your name is hahaha.",
"medium" : "EMAIL",
"asa":"ddddd",
"":""
}
POJO:
package com.innoviti.notification.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
#Document(collection = "NotificationTemplate")
#JsonIgnoreProperties(ignoreUnknown=false)
public class NotificationTemplate {
#JsonCreator
public NotificationTemplate(#JsonProperty(value="notificationType",required=true)String notificationType,
#JsonProperty(value="content",required=true)String content, #JsonProperty(value="medium",required=true)String medium) {
super();
this.notificationType = notificationType;
this.content = content;
this.medium = medium;
}
#Override
public String toString() {
return "NotificationTemplate [id=" + id + ", templateId=" + templateId + ", notificationType="
+ notificationType + ", content=" + content + ", medium=" + medium + "]";
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Id
private String id;
private String templateId;
public String getTemplateId() {
return templateId;
}
public void setTemplateId(String templateId) {
this.templateId = templateId;
}
private String notificationType;
private String content;
private String medium;
public String getMedium() {
return medium;
}
public void setMedium(String medium) {
this.medium = medium;
}
public String getNotificationType() {
return notificationType;
}
public void setNotificationType(String notificationType) {
this.notificationType = notificationType;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
Controller where payload is posted.
#PostMapping(value = "/config", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<NotificationTemplate> configureTemplate(
#Valid #RequestBody NotificationTemplate notificationTemplate) {
NotificationTemplate notificationTemplatePersisted = null;
logger.info(
"Printing payload of template on server side" + ">>>" + notificationTemplate.toString());
try {
validatePayLoad(notificationTemplate);
notificationTemplatePersisted =
notificationTemplateService.createNotificationTemplate(notificationTemplate);
} catch (Exception de) {
logger.info(String.format("Error in saving template", de.getMessage()));
throw new RequestNotCompletedException(de.getLocalizedMessage());
}
return new ResponseEntity<NotificationTemplate>(notificationTemplatePersisted,
HttpStatus.CREATED);
}
Question:How do I validate that an uknown property has been sent as part of payload.In Existing implementation,#RequestBody maps the json without any issue.I want to throw error or validate payload if incoming json is not confirming exactly to POJO.For e.g in payload example i gave,I want to be able to throw error saying that asa is not recognized property
The Jackson property that controls this behaviour is FAIL_ON_UNKNOWN_PROPERTIES. This needs to be true in your case, to get the behaviour you describe.
It seems that since spring boot 1.2 this is set to false by default.
To set it to true add this line to your application.properties file:
spring.jackson.deserialization.fail-on-unknown-properties=true
And then you will get a JsonMappingException when there are extraneous properties in a JSON payload
One can add this class int their project and it would throw an exception if json is mismatched to the pojo class properties.
#Configuration
public class Config implements InitializingBean {
#Autowired
private RequestMappingHandlerAdapter converter;
#Override
public void afterPropertiesSet() throws Exception {
configureJacksonToFailOnUnknownProperties();
}
private void configureJacksonToFailOnUnknownProperties() {
MappingJackson2HttpMessageConverter httpMessageConverter = converter.getMessageConverters().stream()
.filter(mc -> mc.getClass()
.equals(MappingJackson2HttpMessageConverter.class))
.map(mc -> (MappingJackson2HttpMessageConverter) mc)
.findFirst()
.get();
httpMessageConverter.getObjectMapper().enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
}
Ok so I am new to spring and don't really know how this works. I have been trying a few things and think its close to doing it but not getting any data from the server and giving me this error
Unsatisfied dependency expressed through constructor argument with index 4 of type [jp.co.fusionsystems.dimare.crm.service.impl.MyDataDefaultService]: : Error creating bean with name 'MyDataDefaultService' defined in file
My end point
//mobile data endpoint
#RequestMapping(
value = API_PREFIX + ENDPOINT_MyData + "/getMyData",
method = RequestMethod.GET)
public MyData getMyData() {
return MyDataDefaultService.getData();
}
My Object
public class MyData {
public MyData(final Builder builder) {
videoLink = builder.videoLink;
}
private String videoLink;
public String getVideoLink()
{
return videoLink;
}
public static class Builder
{
private String videoLink = "";
public Builder setVideo(String videoLink)
{
this.videoLink = videoLink;
return this;
}
public MyData build()
{
return new MyData(this);
}
}
#Override
public boolean equals(final Object other) {
return ObjectUtils.equals(this, other);
}
#Override
public int hashCode() {
return ObjectUtils.hashCode(this);
}
#Override
public String toString() {
return ObjectUtils.toString(this);
}
}
The Repository
public classMyServerMyDataRepository implements MyDataRepository{
private finalMyServerMyDataJpaRepository jpaRepository;
private final MyDataConverter MyDataConverter = new MyDataConverter();
#Autowired
publicMyServerMyDataRepository(finalMyServerMyDataJpaRepository jpaRepository) {
this.jpaRepository = Validate.notNull(jpaRepository);
}
#Override
public MyData getData() {
MyDataEntity entity = jpaRepository.findOne((long) 0);
MyData.Builder builder = new MyData.Builder()
.setVideo(entity.getVideoLink());
return builder.build();
}
The DefaultService that gets called by the endpoint
public class MyDataDefaultService {
private static final Logger logger = LoggerFactory.getLogger(NotificationDefaultService.class);
private finalMyServerMyDataRepository repository;
#Autowired
public MyDataDefaultService(MyServerMyDataRepository repository) {
this.repository = Validate.notNull(repository);
}
//Get the data from the server
public MobileData getData()
{
logger.info("Get Mobile Data from the server");
//Get the data from the repository
MobileData mobileData = repository.getData();
return mobileData;
}
}
The Converter
public class MyDataConverter extends AbstractConverter<MyDataEntity, MyData>
{
#Override
public MyData convert(MyDataEntity entity) {
MyData.Builder builder = new MyData.Builder()
.setVideo(entity.getVideoLink());
return builder.build();
}
}
My Entity
#Entity
#Table(name = “myServer”)
public class MyDataEntity extends AbstractEntity{
#Column(name = "video_link", nullable = true)
private String videoLink;
public String getVideoLink() {
return videoLink;
}
public void setVideoLink(final String videoLink) {
this.videoLink = videoLink;
}
}
Thank you for any help with this
Hibernate entity should have default constructor defined and implement Serializable interface as well, assume AbstractEntity matches the requirement. Hibernate won't accept an entity without a primary key so you have to define the one too:
#Entity
#Table(name = “myServer”)
public class MyDataEntity implements Serializable {
#Id
#GeneratedValue
private Long id;
#Column(name = "video_link", nullable = true)
private String videoLink;
public MyDataEntity() {
}
...setters&getters
}
MyData object represents the JSON server response, you can use Jackson annotations to control the result JSON properties:
public class MyDataResponse {
#JsonProperty("video_link")
private String videoLink;
public MyDataResponse() {
}
public MyDataResponse(String videoLink) {
this.videoLink = videoLink;
}
...setters&getters
}
Spring has an awesome project so called Spring Data that provides the JPA repositories, so there's no even the #Repository annotation ever needed:
public class MyDataRepository extends CrudRepository<MyDataEntity, Long> {
}
The Builder class represents the Service layer:
#Service
public class MyDataService {
#Autowired
private MyDataRepository myDataRepository;
public MyDataResponse getMyData(Long id) {
MyDataEntity entity = myDataRepository.findOne(id);
...rest logic, copy necessary data to MyDataResponse
}
}
Then a controller is:
#RestController // #ResponseBody not needed when using like this
public MyDataController {
#Autowired
private MyDataService myDataService;
#RequestMapping("/getMyData") // no need to specify method for GET
public MyDataResponse getMyData(#RequestParam("ID") Long myDataId) {
... validation logic
return myDataService.getMyData(myDataId); // return response
}
}
Now it should work, don't forget to add required dependencies to your classpath.
I wrote this Webservice using Spring Data MVC:
Rest Controller
#RestController
#RequestMapping("/textmessages")
public class TextMessageRestController {
#Autowired
private TextMessageService textMessageService;
#RequestMapping(value = "/send", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.CREATED)
public void insertTextMessage(#RequestBody TextMessage.TextMessageDTO textMessageDTO) {
textMessageService.save(textMessageDTO);
}
}
Spring Service
#Service
#Transactional
public class TextMessageService {
#Autowired
private TextMessageRepository textMessageRepository;
#Autowired
private UserService userService;
public void save(TextMessage message) {
textMessageRepository.save(message);
}
public void save(TextMessage.TextMessageDTO textMessageDTO) {
save(from(textMessageDTO));
}
public TextMessage from(TextMessage.TextMessageDTO textMessageDTO) {
User sender = userService.from(textMessageDTO.getSender());
User receiver = userService.from(textMessageDTO.getReceiver());
return new TextMessage(receiver, sender, textMessageDTO.getSymmetricKeyEncrypted(), textMessageDTO.getText());
}
}
DTO - a static inner class
//This annotations are from Lombok
#Getter
#Setter
#AllArgsConstructor(access = AccessLevel.PRIVATE)
public static class SenderReceiverDTO {
private String username;
private String pk;
public static SenderReceiverDTO from(User user) {
SenderReceiverDTO dto = new SenderReceiverDTO(user.username, user.pk);
return dto;
}
}
When I try to consume that REST Service, I get following Exception:
Consuming the rest service
public class RestService {
private static final String REST_STRING = "http://localhost:8080/cchat/";
private static final String TXT_MSG_STRING = REST_STRING + "textmessages/";
private static final String SEND_TXT_MSG = TXT_MSG_STRING + "send/";
private final RestTemplate restTemplate;
public RestService() {
this.restTemplate = new RestTemplate();
}
#SuppressWarnings("unchecked")
public List<TextMessage.TextMessageDTO> loadTextMessages(User.UserIdentifyingDTO userIdentifyingDTO) {
return restTemplate.postForObject(RECEIVE_TXT_MSG, userIdentifyingDTO, List.class);
}
}
i get the excpetion
org.springframework.web.client.HttpClientErrorException: 400 Bad Request
at foo.RestService.sendTextMessage(RestService.java:33)
Tests prove that the server-side is working properly!
Any ideas what may cause the problem?