Unrecognized Property in fetching data from JSONObject in Jersey web service - json

I need to convert a certain JSON string to a Java object. I am using Jackson for JSON handling.
Here is my Java class:
public class RequestClass {
String email_id;
String password;
public String getEmailId() {
return email_id;
}
public String getPassword() {
return password;
}
#Override
public String toString(){
return email_id+" "+password;
}
}
Here is the web service code:
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("/dbconnect3")
public String connectToDbTest3(RequestClass rc) {
System.out.println("connectToDbTest3");
String email_id = rc.getEmailId();
String password = rc.getPassword();
System.out.println(email_id + " " + password);
}
This throws exception UnrecognizedPropertyException with message "Unrecognized field "email_id" (Class jaxrs.RequestClass), not marked as ignorable".
In case i am not using the annotation #JsonIgnoreProperties(ignoreUnknown = true) in my Java class, the output I am getting on line 09 is:
null myPassword
So I don't want to ignore Unrecognized field instead I want to get the value of email_id.
Please tell why It shows email_id as Unrecognized field while password is fetched successfully.

Just add #JsonProperty("email_id") before the getEmailId() like given below:
#JsonProperty("email_id")
public String getEmailId() {
return email_id;
}

Related

Spring - How to convert a String representation of Date in JSON body field in request model comming into controller to OffsetDateTime

I have legacy data coming in to my API as part of UserRequest model like
#PostMapping
public MyResponse saveUser(#Valid #RequestBody UserRequest userRequest) {
...
}
UserRequest class uses OffsetDateTime for dateRegistered field:
public class UserRequest {
...
OffsetDateTime birthDate;
...
}
The problem I am having is that the data is coming into the API using below format for dateRegistered field:
{
"last-name":"Mikel",
"birth-date":"20200716"
}
So, the string representation "20200716" from JSON request needs to be somehow converted to OffsetDateTime like "2020-07-16T00:00:00Z" (the time portion and offset is set to 0s).
By default, the "20200716":
{
"last-name":"Mikel",
"birth-date":"20200716"
}
, gets converted to OffsetDateTime value of
{
"last-name": "Mikel",
"birth-date": "1970-08-22T19:18:36Z"
}
, which is obviously way off.
How do I convert a string representation of date in Json field like "20200716" to its OffsetDateTime representation like "2020-07-16T00:00:00Z" or "2020-07-16T00:00:00.000+00:00"?
I was trying to annotate my OffsetDateTime field with #JsonFormat("yyyyMMdd") but that is throwing exception like: JSON parse error: Cannot deserialize value of type java.time.OffsetDateTime from String "20200716".
you don't need a JSON annotation. You need to adjust the setter as follow.
public class MedicalCandidateRequest {
private OffsetDateTime dateRegistered;
public OffsetDateTime getDateRegistered() {
return dateRegistered;
}
public void setDateRegistered(String dateString) {
final String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSxx";
DateTimeFormatter dtFormatter = DateTimeFormatter.ofPattern(pattern);
this.dateRegistered = OffsetDateTime.parse(dateString, dtFormatter );
}
}
Change the parameter of the setter method to a String and do the conversion yourself.
public void setDateRegistered(String value) {
this.dateRegistered = doConversionHere(value);
}
Thanks for suggestions but I have decided to go with my own implementation.
I provided a custom deserializer like:
public class CustomDateDeserializer extends JsonDeserializer<OffsetDateTime> {
private static final String PATTERN = "yyyyMMdd";
private final DateTimeFormatter formatter;
public CustomDateDeserializer() {
this.formatter = DateTimeFormatter.ofPattern(PATTERN);
}
#Override
public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException, JacksonException {
LocalDate localDate = LocalDate.parse(parser.getText), formatter);
OffsetDateTime offsetDateTime = OffsetDateTime.of(localDate, LocalTime.MIDNIGHT, ZoneOffset.UTC);
return offsetDateTime;
}
}
, which I then use to annotate my model field like:
#JsonDeserialize(using = CustomDateDeserializer.class)
private OffsetDateTime birthDate;

#DateTimeFormat Not working with class member in Spring boot

My pojo class is as given below
public class Employee {
private int empId;
#NotEmpty
private String empName;
#DateTimeFormat(pattern = "dd/MM/yyyy")
private Date empDoj;
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Date getEmpDoj() {
return empDoj;
}
public void setEmpDoj(Date empDoj) {
this.empDoj = empDoj;
}
I am accepting the request in controller as shown below
#RequestMapping(value = "/employee",method = RequestMethod.POST)
public Employee employee(#RequestBody #Valid Employee employee
) {
return employee ;
}
when I am sending the below JSON request from postman it is giving me an error
{
"empName":"Anubhav",
"empDoj":"10/10/2019"
}
JSON parse error: Cannot deserialize value of type java.util.Date from String "10/10/2019": not a valid representation (error: Failed to parse Date value '10/10/2019': Cannot parse date "10/10/2019": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSX", "yyyy-MM-dd'T'HH:mm:ss.SSS", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd")); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type java.util.Date from String "10/10/2019": not a valid representation (error: Failed to parse Date value '10/10/2019': Cannot parse date "10/10/2019": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSX", "yyyy-MM-dd'T'HH:mm:ss.SSS", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd"))
at [Source: (PushbackInputStream); l
when I am doing the same for the method handler
#RequestMapping(value = "/dateformat",method = RequestMethod.POST)
public Date dateex(#DateTimeFormat(pattern = "dd-MM-yyyy") #RequestParam(value = "date")Date date) {
}
It is working fine. Converting string specified in given pattern to Date object then why not with Java class member. In the docs also it says it can be used either at method parameter or field formatted as given date type of field
Since you are sending in JSON you need to add the #JsonFormat(pattern="dd/MM/yyyy") annotation to empDoj. If all your dates will be this format you can set spring.jackson.date-format=dd/MM/yyyy in your application.properties file.
Some details about my vote to close.
You are attempting to use a SpringBoot parameter annotation to specify JSON formatting.
I believe you need to use the JsonFormat annotation
(as noted in the buræquete answer to this question)

How to solve "Error while extracting response for type [class com.*" in Spring Boot?

You might want to skip to my UPDATE 2 bellow
I have a RestController that works, because when I access it directly from the browser, it returns a JSON response. However, when I send a request from a Service in a different bounded context, I get the error:
{"timestamp":1579095291446,"message":"Error while extracting response for type
[class com.path.to.contexttwo.client.dto.WorkerDetails] and content type [application/json]; nested exception is
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error:
Unexpected character ('<' (code 60)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false');
nested exception is com.fasterxml.jackson.core.JsonParseException:
Unexpected character ('<' (code 60)):
expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\n at [Source: (PushbackInputStream);
line: 1, column: 2]","details":"uri=/context-two/register-new"}
Here is my code:
RestController
package com.path.to.contextone.aplication.presentation;
#RestController
#RequestMapping(path = "/iacess", produces = "application/json")
#CrossOrigin(origins = "*")
public class IAccessRestController {
UserRepository userRepo;
IAcessService iaccessService;
EntityLinks entityLinks;
#Autowired
public IAccessRestController(
UserRepository userRepo,
IAcessService iaccessService,
EntityLinks entityLinks) {
this.userRepo = userRepo;
this.iaccessService= iaccessService;
this.entityLinks = entityLinks;
}
#GetMapping("/get-worker-details/{userName}")
public WorkerDetails getWorkerDetails(#PathVariable String userName) {
User user = userRepo.findByUsername(userName);
WorkerDetails workerDetails = new WorkerDetails();
workerDetails.setUserId(userId);
workerDetails.setGender(user.gender());
workerDetails.setFirstName(user.getFirstName());
workerDetails.setLastName(user.getLastName());
workerDetails.setPhoneNumber(user.getPhoneNumber());
if (workerDetails != null) {
return workerDetails;
}
return null;
}
}
RestClient
package com.path.to.contexttwo.client;
// imports omitted, as well as other code
#Service
public class IAcessRestClientImpl implements IAcessRestClient {
private final RestTemplate restTemplate;
#Autowired
public IAcessRestClientImpl(
final RestTemplate restTemplate
) {
this.restTemplate = restTemplate;
}
#Override
public WorkerDetails getWorkerDetailsByName(final String userName) throws URISyntaxException {
Map<String,String> urlVariables = new HashMap<>();
urlVariables.put("userName", userName);
return restTemplate.getForObject(
"http://localhost:8080/iacess/get-worker-details/{userName}",
WorkerDetails.class,
urlVariables
);
}
}
Config
package com.path.to.contexttwo.configuration;
#Configuration
#EnableWebMvc
public class RestClientConfig {
#Bean
public RestTemplate restTemplate() {
final RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
List<MediaType> mediaTypes = new ArrayList<MediaType>();
mediaTypes.add(MediaType.APPLICATION_JSON);
converter.setSupportedMediaTypes(mediaTypes);
messageConverters.add(converter);
restTemplate.setMessageConverters(messageConverters);
restTemplate.getInterceptors().add(new JsonInterceptor());
return restTemplate;
}
}
WorkerDetails
package com.path.to.contexttwo.client.dto;
import java.io.Serializable;
import java.util.Objects;
public class WorkerDetails implements Serializable {
private long userId;
private String gender;
private String firstName;
private String lastName;
private String phoneNumber;
public WorkerDetails() {
this.userId = -1;
this.gender = null;
this.firstName = null;
this.lastName = null;
this.phoneNumber = null;
}
// omitted all args constructor, getters, setters, equals, hascode, toString for simplicity
}
WorkerDetails also exists in package com.path.to.contextone.ohs_pl;
I've been trying for 3 days, reading and debugging, to no avail. Debugger seems to show that the error happens when RestTemplate is analysing the WorkerDetails.class.
I also tried using ComponentScan in all configuration classes, because files are in separate packages (bounded contexts), without success.
I could just use the UserDetailsRepository from the class that calls IAcessRestClient to get the WorkerDetails, but this would make two different bounded contexts depend on the same database schema.
Any help would be very appreciated.
I can post aditional code per request.
Thanks in advance
UPDATE
#S B ask for input params. here goes the class that sends the params:
CompanyServiceImpl
package com.path.to.contexttwo.domain.services;
// imports
#Service
public class CompanyServiceImpl implements CompanyService {
private CompanyRepository companyRepository;
private CompanyWorkerRepositoery companyWorkerRepositoery;
private WorkerDetailsClient workerDetailsClient;
private WebApplicationContext applicationContext;
#Autowired
CompanyServiceImpl (
CompanyRepository companyRepository,
CompanyWorkerRepositoery companyWorkerRepositoery,
WorkerDetailsClient workerDetailsClient,
WebApplicationContext applicationContext
) {
this.companyRepository = companyRepository;
this.companyWorkerRepositoery = companyWorkerRepositoery;
this.workerDetailsClient = workerDetailsClient;
this.applicationContext = applicationContext;
}
#Transactional
public Company criateCompany(CompanyDTO dto) throws URISyntaxException {
if (dto.getLegalyAuthorized() == true && dto.getTerms() == true) {
Company company = new Company(
dto.getCompanyName(),
dto.getStateId()
);
company = CompanyRepository.save(company);
// when saving the company, we also need some details from the current logged in user which can be
// retrieved from the idendity and access bounded context. We need those details to be saved in this context
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName();
WorkerDetails workerDetails = WorkerDetailsClient.getWorkerDetailsByName(
name
);
// ... we can't reach the rest of the code anyway, so we omitted
}
}
And here is the response I get when acessing the RestController directly:
{"userId":127,"gender":"M","firstName":"Primeiro","lastName":"Último","phoneNumber":"922222222"}
UPDATE 2
Commented out .anyRequest().authenticated() and everything runned OK! So, it has to do with Spring Security all this time. What a shame. Will now try to make things work with security enabled. I was receiving HTML as response because of redirection to login page. Implemented authentication correctly (token request with basic auth) and everything works well.
Thank you all!
Try:
return restTemplate.getForObject(
"http://localhost:8080/iacess/get-worker-details/" + userName,
WorkerDetails.class);

JSON parsing unexpectedly passing when sending POST to REST service

I have built a REST service using Spring-Boot. Everything works fine. However, when I update my curl command to POST erroneous names for my POJO variables, I get an object with default values.
My entity looks like:
#Entity
public class UserTask {
#Id
private Long userId;
private int numComplete;
private int numIncomplete;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public int getNumComplete() {
return numComplete;
}
public void setNumComplete(int numComplete) {
this.numComplete = numComplete;
}
public int getNumIncomplete() {
return numIncomplete;
}
public void setNumIncomplete(int numIncomplete) {
this.numIncomplete = numIncomplete;
}
#Override
public String toString() {
return new StringBuilder("[id : ").append(getUserId())
.append(", complete : ").append(getNumComplete())
.append(", incomplete : ").append(getNumIncomplete())
.append("]").toString();
}
}
I execute a POST against my service like so:
curl -i -X POST -H "Content-Type:application/json" -d "{ \"uId\" : \"1\", \"numC\" : \"3\", \"numI\" : \"2\" }" http://localhost:8080/user-task
The returned status for the POST is 201 and the record is written (in this case updated) in the database. When I debug, I see that the UserTask instance passed into the REST controller method has default value null for userId, 0 for numComplete and 0 for numIncomplete. I thought that the JSON parser would've failed when it couldn't unmarshal the POST JSON content as a UserTask instance?
You can use JSONSchema to validate the #RequestBody or #Valid of Hibernate Validator, so if the POJO doesn't met this validations you could Thrown a Exception of RequiredParameters for example.
yourMethod(#RequestBody #Valid UserTask)

rest api returns empty bracket for GET request

I implemented Rest api with Spring Boot. In my controller class, I have code to handle GET request which will return JSON if record found.
// SeqController.java
#Autowired
private SeqService seqService;
#RequestMapping(
value = "/api/seqs/{analysis_id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<SeqTb>> getSeqByAnalysisId(#PathVariable("analysis_id") String analysis_id) {
List<SeqTb> seqs = seqService.findByAnalysisId(analysis_id);
return new ResponseEntity(seqs, HttpStatus.OK);
}
I also create a bean class SeqServiceBean that extends the interface SeqService which in turn calls methods from the following JPA repository for query.
//SeqRepository.java
#Repository
public interface SeqRepository extends JpaRepository<SeqTb, Integer> {
#Override
public List<SeqTb> findAll();
public List<SeqTb> findByAnalysisId(String analysisId);
}
Problem is when I typed the url (http://localhost:8080/api/seqs/fdebfd6e-d046-4192-8b97-ac9f65dc2009) in my browser, it returned nothing but a pair of empty brackets. I just looked in the database and that record is indeed there. What did I do wrong?
A bit late to answer this quesiton, but in case anyone else is having this issue.
This problem may be caused by the class (that we want to be displayed as a json object) missing getter and/or setter methods.
In your case the "seqTab" class may be not have getters.
Without the getters our application can not extract the fileds to build the json object.
Example :
Sample user class
public class User {
private String firstname;
private String lasttname;
int age;
public User(){
}
public User(String fname, String lname, int age){
this.firstname = fname;
this.lasttname = lname;
this.age = age;
}
}
Sample rest controller
#RestController
public class SampleRS {
#RequestMapping(value = {"/sample/{input}"}, method = RequestMethod.GET , produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> startService(#PathVariable("input") String input){
User u = new User(input,"bikila",45);
return new ResponseEntity<User>(u,HttpStatus.OK);
}
}
// If we try to hit the endpoint /sample{input} .. e.g.
Request : localhost:8080/Sample/abebe
Response :
{}
But adding the getters for the User class will solve the problem.
Modified User class with getters
public class User {
private String firstname;
private String lasttname;
int age;
public User(){
}
public User(String fname, String lname, int age){
this.firstname = fname;
this.lasttname = lname;
this.age = age;
}
public String getFirstname() {
return firstname;
}
public String getLasttname() {
return lasttname;
}
public int getAge() {
return age;
}
}
Request : http://localhost:8080/sample/abebe
Response : {"firstname":"abebe","lasttname":"bikila","age":45}
Hope that helps !
In most of case, database driver jar is not deployed in server. Check deployment assembly of project in eclipse. Also see console message to check if it is showing driver jar not found.
If this is case simply deploy this jar in deployment assembly of eclipse.
One thing, if build path has this jdbc driverjar in eclipse, main method will connect to database. But if jar is not deployed jdbc connection will not happen over http request.