I have added new fields to POJO expecting to find them in response in my Spring Boot application. It is a simple POJO with Lombok annotations:
#Getter
#Setter
#NoArgsConstructor
public class Responce implements AsyncResponse, Serializable {
private String resultCode;
private String errorCode; // added field
public Responce(String resultCode) {
this.resultCode = resultCode;
}
}
In my service method I have created object and then used a setter for added extra field errorCode:
Responce response = new Responce("0");
responce.setErrorCode("777");
But I still receive a JSON with one field:
{
resultCode: "0"
}
How I can force to include new field?
UPD:
AsyncResponse looks like this
public interface AsyncResponse {
String getResultCode();
void setResultCode(String resultCode);
String getErrorCode(); // added getter
void setErrorCode(String errorCode); // added setter
}
There was a filter set up in application.yml in gateway module which hadn't mentioned fields in fieldsToRetain parameter.
Related
I am calling a third party REST endpoint. The request for the thrid party REST endpoint looks like this.
{
"body": {
"accountNumber": "12345"
},
"header": {
"username": "someusername",
"password": "somepassword"
}
}
I have created 3 bean classes
MyRequest.java
#Builder
#JsonDeserialize(builder = MyRequest.MyRequestBuilder.class)
public class MyRequest {
#JsonProperty("header")
private MyHeader header;
#JsonProperty("body")
private MyBody body;
}
MyBody.java
#Getter
#Builder
public class MyBody {
private String accountNumber;
}
MyHeader.java
#Getter
#Builder
public class MyHeader {
private String username;
private String password;
}
I'm creating request object using
MyBody body = MyBody.builder().accountNumber("12345").build();
MyHeader header = MyHeader.builder().username("someusername").password("somepassword").build();
MyRequest request = MyRequest.builder().body(body).header(header).build();
I'm calling the 3rd part REST endpoint using the below code
HttpEntity<MyRequest> httpEntity = new HttpEntity<>(myRequest, httpHeaders);
String url = "someurl";
someResponse = this.restTemplate.postForObject(url, httpEntity,
SomeResponse.class);
I'm getting proper response. But if I remove #Getter annotation from MyHeader and MyBody, 3rd party REST endpoint is getting null values in request. Why #Getter is necessary here. How to make this work without #Getter.
if I remove #Getter annotation from MyHeader and MyBody, 3rd party REST endpoint is getting null values in request. Why #Getter is necessary here. How to make this work without #Getter.
You need to instruct Jackson somehow which data should be included during serialization. The default mechanism is to use getters for that purpose.
That's not the only way.
Alternatively, you can annotate certain fields with #JsonProperty, or change the default visibility of the fields either globally or for a particular type using annotation #JsonAutoDetect and set its property fieldVisibility to ANY (that would make the fields discoverable even in the absence of getters)
The key point is that the information on which data needs to be present in the serialized JSON should be provided somehow, and it doesn't matter how exactly.
Consider a dummy POJO with no getters:
#AllArgsConstructor
public class Foo {
#JsonProperty
private String bar;
}
Property bar would be reflected in the resulting JSON.
ObjectMapper mapper = new ObjectMapper();
Foo foo = new Foo("baz");
String jsonFoo = mapper.writeValueAsString(foo);
System.out.println(jsonFoo);
Output:
{"bar":"baz"}
Now, if we remove #JsonProperty (no getters as before) that's what would happen.
#AllArgsConstructor
public class Foo {
private String bar;
}
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
Foo foo = new Foo("baz");
String jsonFoo = mapper.writeValueAsString(foo);
System.out.println(jsonFoo);
Output:
{}
An empty Bean produces an empty JSON (or raises an exception, depending on configuration). And vise versa, Deserialization of an empty JSON gives an empty Bean.
I'm working on the Spring application with Angular frontend. I'm trying to send a POST request to update data in the database but there is an exception:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot
construct instance of UpdateRecipesDTO
There is the DTO class that I receive from the frontend part:
#Data
public class UpdateRecipesDTO {
private String query;
private String meal;
private String dish;
private String cuisine;
}
And it goes to the controller method
#PostMapping(value = "/recipe-update")
public int updateByAdmin(HttpServletRequest request, #RequestBody UpdateRecipesDTO updateRecipesDTO) {
System.out.println("You're here");
}
Now the only that I want is a printed string but it doesn't print anything. I had tried to use #AllArgsConstructor Lombok annotation, but it didn't work. Writing AllArgsConstructor by myself didn't help also. So what should I do?
I'm sending a POST-Request from angular to spring. Its getting deserialized mostly correct, but one nested object is getting deserialized as an empty Object.
My Angular interfaces look as follows:
// ClientMedicalModal.ts
export interface ClientMedicalModal {
clientMedicalId: number;
client: ClientModel;
medicalEvidence: MedicalEvidence;
}
// ClientModal.ts
export interface ClientModal {
clientId: number;
}
// MedicalEvidenceModal.ts
export interface MedicalEvidenceModal {
B001: string;
B003: string;
B004: string;
}
My Java-Objects look like this:
public class ClientMedical implements Serializable {
private Integer clientMedicalId;
private Client client;
private MedicalEvidence medicalEvidence;
// getter and setter
}
public class Client implements Serializable {
private Integer clientId;
// getter and setter
}
public class MedicalEvidence implements Serializable {
private String B001;
private String B003;
private String B004;
public String getB001() {
return B001;
}
public MedicalEvidence setB001(String b001) {
B001 = b001;
}
// all other getter and setter
}
When I check the post message from my browser everything seems to be okay:
{"medicalEvidence":{"B001":"Test","B003":"TestMessage","B004":"Whatever"},"client":{"clientId":1}}
Debugging in Spring I get the request, there is a Client-Object with clientId = 1, but the ClientEvidence-Object is empty, all B00* fields are null.
See here the debugging values
Spring form binding binds the form parameters to respective fields for Client class, but MedicalEvidence is blank, so Spring instantiates a new MedicalEvidence class with all fields having null values. Why does the parameters does not get bound to the MedicalEvidence's class fields but to Client's class (and all other classes I'm using the same way)? Btw. It does not work either if I just send MedicalEvidence from Angular. The object params are still all empty.
Try using b001, b002,.. as names, the first letter should not be uppercase in your use case, except you want to use some annotation. And use 'this.' in the setter method.
public class MedicalEvidence implements Serializable {
private String b001;
private String b003;
private String b004;
^^^^
public String getB001() {
return b001;
}
public MedicalEvidence setB001(String b001) {
this.b001 = b001;
^^^^^
}
I am new to spring rest and am having problem to map JSON object from jquery to controller. My jquery JSON object have some field absent which are present in java object on controller. Do I have to create new class to map such object or is there any way to map these objects without creating new class?
Here are the code
Controller:
#RequestMapping(value = "/createTest", method = RequestMethod.POST,consumes="application/json")
#ResponseBody
public String createTest(#RequestBody TestJsonDTO testJson)
throws JsonProcessingException, IOException {
//....
TestJsonDTO:
public class TestJsonDTO {
private TestSet testSet;
private List<MainQuestion> questionsInTest;
//gettters and setters
TestSet:
public class TestSet implements Serializable {
public TestSet() {
}
#Id
#GeneratedValue
private int id;
private String name;
private int fullmark;
private int passmark;
String duration;
Date createDate = new Date();
Date testDate;
boolean isNegativeMarking;
boolean negativeMarkingValue;
MainQuestion:
public class MainQuestion implements Serializable {
private static final long serialVersionUID = 1L;
public MainQuestion() {
}
#Id
#GeneratedValue
private int id;
private String name;
and my jquery post method
function createTest() {
$.ajax({
type : 'POST',
url : "http://localhost:8085/annotationBased/admin/createTest",
dataType : "json",
contentType : "application/json",
data : testToJSON(),
success : function() {
alert("success")
},
error : function(msg) {
alert("error while saving test");
}
});
}
function testToJSON() {
listOfQuestionForTest = questionToAdd;//array of ids of questions
return JSON.stringify({
"testSet.name" : $('#testname').val(),
"testSet.fullmark" : parseInt($('#fullmark').val()),
"testSet.passmark" : parseInt($('#passmark').val()),
"questionsInTest" : listOfQuestionForTest
// "testDate":$('#testDate').value()
})
}
In JSON.stringify I am not sending all the fields in TestJsonDto. How can I map this?
You should configure Spring this way:
#Configuration
public class ServiceContext
extends WebMvcConfigurationSupport {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = this.getMappingJackson2HttpMessageConverter();
converters.add(converter);
}
#Bean
public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = this.getObjectMapper();
mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
return mappingJackson2HttpMessageConverter;
}
#Bean
public ObjectMapper getObjectMapper() {
JsonFactory jsonFactory = new JsonFactory();
ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // this is what you need
objectMapper.setSerializationInclusion(Include.NON_NULL); // this is to not serialize unset properties
return objectMapper;
}
}
Here Spring is configured with an ObjectMapper that doesn't serialize properties whose value is null and that doesn't fail on deserialization if some property is missing.
EDIT: (Added some background and explanations)
Spring converts what comes in HTTP request's body into a POJO (that's what #RequestBody actually tells Spring to do). This conversion is performed by a HttpMessageConverter, which is an abstraction. Spring provides default specific message converters for common media types, such as Strings, JSON, form fields, etc.
In your case, you need to tell Spring how to deserialize the incoming JSON, i.e. how to read the JSON that you're sending from jQuery and how to convert this JSON into the POJO you're expecting to receive in your #Controller (TestJsonDTO in your question).
Jackson 2 is a JSON serialization/deserialization library that is widely used. It's most important class is ObjectMapper, which is used to perform the actual serialization and deserialization. Spring has a specific HttpMessageConverter that uses Jackson in order to serialize and deserialize JSON. This is MappingJackson2HttpMessageConverter, which can receive a Jackson's ObjectMapper instance that you can configure if you want to override default behavior.
This ObjectMapper is configured to not serialize properties that are null in your POJO (i.e. your JSON won't contain these properties as fields), and more important, when deserializing, it is configured to not fail with an exception if there is a missing property in either your JSON or your POJO. This is what objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); actually does.
i have an class with the following annotations:
class A {
public Map<String,List<String>> references;
#JsonProperty
public Map<String,List<String>> getReferences() {
...
}
#JsonIgnore
public void setReferences(Map<String,List<String>>) {
}
...
}
}
What I try is to ignore the json on deserialization. But it doesn't work. Always when JSON String arrives the Jackson lib fill the references attribute. If I use only the #JsonIgnore annotation the getter doesn't work. Are there any solutions for this problem?
Thanks
I think there are two key pieces that should enable you to have "read-only collections" as desired. First, in addition to ignoring the setter, ensure that your field is also marked with #JsonIgnore:
class A {
#JsonIgnore
public Map<String,List<String>> references;
#JsonProperty
public Map<String,List<String>> getReferences() { ... }
#JsonIgnore
public void setReferences(Map<String,List<String>>) { ... }
}
Second, in order to prevent the getters from being used as setters, disable the USE_GETTERS_AS_SETTERS feature:
ObjectMapper mapper = new ObjectMapper();
mapper.disable(MapperFeature.USE_GETTERS_AS_SETTERS);
As of Jackson 2.6, there is a new and improved way to define read-only and write-only properties, using JsonProperty#access() annotation. This is recommended over use of separate JsonIgnore and JsonProperty annotations.
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
public Map<String,List<String>> references;
You have to make sure there is #JsonIgnore annotation on the field level as well as on the setter, and getter annotated with #JsonProperty.
public class Echo {
#Null
#JsonIgnore
private String doNotDeserialise;
private String echo;
#JsonProperty
public String getDoNotDeserialise() {
return doNotDeserialise;
}
#JsonIgnore
public void setDoNotDeserialise(String doNotDeserialise) {
this.doNotDeserialise = doNotDeserialise;
}
public String getEcho() {
return echo;
}
public void setEcho(String echo) {
this.echo = echo;
}
}
#Controller
public class EchoController {
#ResponseBody
#RequestMapping(value = "/echo", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
public Echo echo(#RequestBody #Valid Echo echo) {
if (StringUtils.isEmpty(echo.getDoNotDeserialise())) {
echo.setDoNotDeserialise("Value is set by the server, not by the client!");
}
return echo;
}
}
If you submit a JSON request with a “doNotDeserialise” value set to something, when JSON is deserialised to an object it will be set to null (if not I put a validation constraint on the field so it will error out)
If you set the “doNotDeserialise” value to something on the server then it will be correctly serialised to JSON and pushed to the client
I used #JsonIgnore on my getter and it didn't work and I couldn't configure the mapper (I was using Jackson Jaxrs providers). This worked for me:
#JsonIgnoreProperties(ignoreUnknown = true, value = { "actorsAsString",
"writersAsString", "directorsAsString", "genresAsString" })
I can only think of a non-jackson solution, to use a base class that does not have references for the mapping and then cast to the actual class:
// expect a B on an incoming request
class B {
// ...
}
// after the data is read, cast to A which will have empty references
class A extends B {
public Map<String,List<String>> references;
}
Why do you even send the References if you don't want them?
Or is the incoming data out of your hands and you just want to avoid the mapping exception telling you that jackson cannot find a property to set for incoming references? For that we use a base class which all of our Json model classes inherit:
public abstract class JsonObject {
#JsonAnySetter
public void handleUnknown(String key, Object value) {
// for us we log an error if we can't map but you can skip that
Log log = LogFactory.getLog(String.class);
log.error("Error mapping object of type: " + this.getClass().getName());
log.error("Could not map key: \"" + key + "\" and value: \"" + "\"" + value.toString() + "\"");
}
Then in the POJO you add #JsonIgnoreProperties so that incoming properties will get forwarded to handleUnknown()
#JsonIgnoreProperties
class A extends JsonObject {
// no references if you don't need them
}
edit
This SO Thread describes how to use Mixins. This might be the solution, if you want to keep your structure exactly as it is, but I have not tried it.