Jackson ObjectMapper readValue() unrecognized field when parsing to Object - java

I am creating simple rest client in Java/Spring. My request has been consumed properly by remote service and I got the response String something:
{"access_token":"d1c9ae1b-bf21-4b87-89be-262f6","token_type":"bearer","expires_in":43199,"grant_type":"client_credentials"}
The code below is the Object where I want to bind values from Json Response
package Zadanie2.Zadanie2;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Token {
String access_token;
String token_type;
int expiresIn;
String grantType;
//////////////////////////////////////////////////////
public Token() {
/////////////////////////////////
}
/////////////////////////////////////////////////////
public void setAccessToken(String access_token) {
this.access_token=access_token;
}
public String getAccessToken() {
return access_token;
}
////////////////////////////////////////////////
public void setTokenType(String token_type) {
this.token_type=token_type;
}
public String getTokenType() {
return token_type;
}
//////////////////////////////////////////////////////
public void setExpiresIn(int expiresIn) {
this.expiresIn=expiresIn;
}
public int getExpiresIn() {
return expiresIn;
}
//////////////////////////////////////////////////////////
public void setGrantType(String grantType) {
this.grantType=grantType;
}
public String getGrantType() {
return grantType;
}
}
all the time I am getting "unrecognized field access_token" but when I add objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
then access_token will be null
jsonAnswer=template.postForObject(baseUriAuthorize, requestEntity, String.class);
System.out.println(jsonAnswer);
Token token=objectMapper.readValue(jsonAnswer, Token.class);
System.out.println(token.getAccessToken());
I tried with #JsonProperty annotations. I tried with changing field by for example "#JsonProperty(accessToken)" because I thought there is an issue with "_" sign in variable name. I added getters and setters. Maybe there is a problem with the version I use but I don't think so because I am using "com.fasterxml.jackson.core"

You tried with "#JsonProperty(accessToken)". But your json contains access_token. how it works?
Try with this class:
public class Token {
#JsonProperty("access_token")
String accessToken;
#JsonProperty("token_type")
String tokenType;
int expiresIn;
String grantType;
//getter setter
}

Your setters do not match with the JSON key.
To read it correctly, you should change your setters to:
setAccess_token()
setToken_type()
...
But honestly, this is so ugly.
Try following the Java bean name convention and customize the JSON key with #JsonProperty:
public class Token {
#JsonProperty("access_token")
String accessToken;
....
}

Related

How to Use DI to get a final variable as #PostMapping's path

I have a final class Constants, which holds some final data.
#Component
public final class Constants {
public final String TOKEN;
public final String HOST;
public final String TELEGRAM;
public Constants(#Value("${myapp.bot-token}") String token,
#Value("${myapp.host}") String host) {
this.TOKEN = token;
this.HOST = host;
this.TELEGRAM = "https://api.telegram.org/bot" + TOKEN;
}
}
The problem is that, when I want to use a variable as #PostMapping path, I faced this error:
Attribute value must be constant
#RestController
#RequestMapping
public class Controller {
private final Constants constants;
#Autowired
public Controller(Constants constants) {
this.constants = constants;
}
#PostMapping(constants.TOKEN)// Problem is here
public ResponseEntity<?> getMessage(#RequestBody String payload) {
return new ResponseEntity<HttpStatus>(HttpStatus.OK);
}
}
I've tried to load TOKEN in my controller class but faced the same issue.
#RestController
#RequestMapping
public class Controller {
#Value("${myapp.bot-token}") String token
private String token;
#PostMapping(token)// Problem is here
public ResponseEntity<?> getMessage(#RequestBody String payload) {
return new ResponseEntity<HttpStatus>(HttpStatus.OK);
}
}
When I do something like this the problem will gone. But I don't want to declare my token in source-code.
#RestController
#RequestMapping
public class Controller {
private final String TOKEN = "SOME-TOKEN";
#PostMapping(TOKEN)// No problem
public ResponseEntity<?> getMessage(#RequestBody String payload) {
return new ResponseEntity<HttpStatus>(HttpStatus.OK);
}
}
Can anyone please give me a solution to this?
Try to paste string with property path inside #PostMapping annotation. Like this
#GetMapping(value = "${app.path}")
public String hello() {
return "hello";
}
You can only use a constant (i.e. a final static variable) as the parameter for an annotation.
Example:
#Component
class Constants {
public final static String FACEBOOK = "facebook";
}
#RestController
class Controller {
#PostMapping(Constants.FACEBOOK)
public ResponseEntity<ResponseBody> getMessage(#RequestBody String payload) {
return new ResponseEntity<>(HttpStatus.OK);
}
}
You must use builder pattern(use Lombok for ease) and freeze the value that you are getting from the properties and then use that in your program.

Variables are not coming up null during Postman call

Setting up an Java Postman call assigning values to the variables but its shows null.
#PostMapping("/caStudents/student")
public String generateSignedValue(#RequestBody StudentRequest studentRequest) throws Exception
String signedValue=studentService.getSignedValue(studentRequest);
return signedValue;
My Pojo Student Class
public class StudentRequest {
String user;
Long duration ;
public String getPublicKey() {
return publicKey;
}
public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public Long getDuration() {
return duration;
}
public void setDuration(Long duration) {
this.duration = duration;
}
Postman Request
{"studentRequest":[{"user":"admin","duration":19336}]}
your request body should be like this:
{"user":"admin","duration":19336}
because you are getting StudentRequest as RequestBody and it means you should send StudentRequest internal properties not containing StudentRequest it self in request ,
second problem is that your RequestBody contains singular object not array .
According to what you've given us your request should actually be
{
"user": "admin",
"duration": 19336
}
If you want to provide multiple student requests at once (within an array), then you're StudenRequest class should look somewhat like this:
public class StudentRequest {
List<StudentR>;
// Getter and Setter or not in case you use lombok
class StudenR {
String user;
Long duration ;
}
}

JSON.decodeValue Decode Exception

I want to make this java code works:
RequestManager rm = Json.decodeValue(request.getBodyAsString(), RequestManager.class);
But i have this error:
io.vertx.core.json.DecodeException: Failed to decode:No suitable constructor found for type [simple type, class RequestManager]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: {"messageId":"fsdfsdf"}; line: 1, column: 2]
And here the code of my class :
public class RequestManager {
private String messageId;
private String messageContent;
public RequestManager(String messageId, String messageContent) {
this.messageId = messageId;
this.messageContent = messageContent;
}
public String getMessageId() {
return messageId;
}
public String getMessageContent() {
return messageContent;
}
}
I really don't know why it's not working and there is only few topics about it, but they were irrelevant.
Someone can help ?
EDIT--
I know have the RequestManager class like this:
public class RequestManager {
private String messageId;
private String messageContent;
public RequestManager(String messageId, String messageContent) {
this.messageId = messageId;
this.messageContent = messageContent + "check";
}
public RequestManager() {
}
public String getMessageId() {
return messageId;
}
public String getMessageContent() {
return messageContent;
}
public void setMessageId(String messageId) {
this.messageId = messageId;
}
public void setMessageContent(String messageContent) {
this.messageContent = messageContent;
}
}
But know when i try to print the fields of my RequestManager object created with the JSON.decodeValue it's return me null. I've already done that in the past and had the same error. I think it's because the empty constructor is used instead.
I still don't really understand....
EDIT--2
I have tried to change my class again, here it is:
#JsonIgnoreProperties(ignoreUnknown=true)
public class RequestManager {
#JsonProperty("messageId") private String messageId;
#JsonProperty("messageContent") private String messageContent;
#JsonCreator
public RequestManager(#JsonProperty("messageId") String messageId, #JsonProperty("messageContent") String messageContent) {
this.messageId = messageId;
this.messageContent = messageContent;
System.out.println("This constructor is used.");
}
public RequestManager() {
}
public String getMessageId() {
return messageId;
}
public String getMessageContent() {
return messageContent;
}
public void setMessageId(String messageId) {
this.messageId = messageId;
}
public void setMessageContent(String messageContent) {
this.messageContent = messageContent;
}
}
And this is in my main :
final RequestManager rm = Json.decodeValue("{\"messageId\":\"themessage\"}", RequestManager.class);
System.out.println(rm.getMessageContent());
"{\"messageId\":\"themessage\"}" = the JSON format, i'm sure of it because decodeValue would return a Decode Exception if it wasn't.
Now the field is "nullcheck" when i print it. So it means that the constructor is well used but the fields are nulls. Where am i doint it wrong ?
You could try to have an empty constructor.
It's because you have your own constructor, and JSON doesn't know what values should be passed into it.
There is documentation on their GitHub page explaining how to set up a data object that you expect to be given to you as JSON and converted to Java.
https://github.com/vert-x3/vertx-codegen#data-objects
As per the example that you linked to: http://vertx.io/blog/some-rest-with-vert-x/, notice how they explicitly provide a constructor that takes no arguments, and public setter methods
Whisky()
setName(String name)
setOrigin(String origin)
The alternative is to provide annotations: https://github.com/FasterXML/jackson-annotations. You can choose how to do it, using annotation if you want, or using a bean class (getters and setters). Annotation has the advantage that you can say things like "ignore this value when you convert to JSON", etc. You can be more explicit with annotation. I would recommend picking one and staying with it. Consistency becomes important as your projects grow.

Mapping JSON into POJO using Gson

I have the following JSON to represent the server response for a salt request:
{
"USER":
{
"E_MAIL":"email",
"SALT":"salt"
},
"CODE":"010"
}
And i tried to map it with the following POJO:
public class SaltPOJO {
private String code = null;
private User user = null;
#Override
public String toString() {
return this.user.toString();
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public class User {
private String e_mail = null;
private String salt = null;
#Override
public String toString() {
return this.e_mail + ": " + this.salt;
}
public String getE_mail() {
return e_mail;
}
public void setE_mail(String e_mail) {
this.e_mail = e_mail;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
}
}
Now everytime i do this:
Gson gson = new Gson();
SaltPOJO saltPojo = gson.fromJson(json.toString(), SaltPOJO.class);
Log.v("Bla", saltPojo.toString());
The saltPojo.toString() is null. How can i map my JSON into POJO using Gson?
Is the order of my variables important for the Gson mapping?
Is the order of my variables important for the Gson mapping?
No, that's not the case.
How can i map my JSON into POJO using Gson?
It's Case Sensitive and the keys in JSON string should be same as variable names used in POJO class.
You can use #SerializedName annotation to use any variable name as your like.
Sample code:
class SaltPOJO {
#SerializedName("CODE")
private String code = null;
#SerializedName("USER")
private User user = null;
...
class User {
#SerializedName("E_MAIL")
private String e_mail = null;
#SerializedName("SALT")
private String salt = null;
You don't have proper mapping between your getter and setter. If you change your json to something like below, it would work:
{
"user":
{
"email":"email",
"salt":"salt"
},
"code":"010"
}
If you are getting json form third party then unfortunately, you would have to change your pojo or you could use adapter.

Serializing JSON string to object

I am trying to parse through a JSON string and convert it to the following POJO:
package apicall;
//POJO representation of OAuthAccessToken
public class OAuthAccessToken {
private String tokenType;
private String tokenValue;
public OAuthAccessToken(String tokenType,String tokenValue) {
this.tokenType=tokenType;
this.tokenValue=tokenValue;
}
public String toString() {
return "tokenType="+tokenType+"\ntokenValue="+tokenValue;
}
public String getTokenValue() {
return tokenValue;
}
public String getTokenType() {
return tokenType;
}
}
In order to do this I have written the following code:
Gson gson=new Gson();
String responseJSONString="{\"access_token\" : \"2YotnFZFEjr1zCsicMWpAA\",\"token_type\" : \"bearer\"}";
OAuthAccessToken token=gson.fromJson(responseJSONString, OAuthAccessToken.class);
System.out.println(token);
When I run the code, I get the following output:
tokenType=null
tokenValue=null
Instead of
tokenType=bearer
tokenValue=2YotnFZFEjr1zCsicMWpAA
I don't understand if there's anything I've done wrong. Please help.
You can get the expected result by annotating your fields like:
#SerializedName("token_type")
private final String tokenType;
#SerializedName("access_token")
private final String tokenValue;
How is Gson supposed to know how to populate your object? You don't have a no-arg constructor, and the fields of your object don't match the fields in the JSON object.
Make your object as following:
public class OAuthAccessToken {
private String accessToken;
private String tokenType;
OAuthAccessToken() {
}
...
}
The class should have the exact field name as the json, so if your json have 2 keys: "access_token" and "token_type", the class should have 2 fields:
private String access_token;
private String token_type;
And, of course you need to change the getters/setters accordingly.

Categories