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.
I have superclass:
#Getter
#Setter
public abstract class AbstractDto {
#NotNull
protected String num;
}
And subclass:
#Getter
#Setter
public class SomeDto extends AbstractDto {
#NotNull
private Long id;
}
When I serialize it, all is ok:
{"num":"5600511164","id":22}
But when I try to deserialize, I get all fields as null in SomeDto.
I use this configuration
#Bean
public ObjectMapper objectMapper (Jackson2ObjectMapperBuilder builder) {
return builder.createXmlMapper(false).build();
}
I think problem is in use superclass, but I don't know how to fix it. Without superclass always work fine.
UPD.
Serialize like this:
protected String marshall(Object message) throws JsonProcessingException {
return this.objectMapper.writeValueAsString(message);
}
Deserialize like this:
protected T unmarshall(byte[] body) throws IOException {
return objectMapper.readValue(body, resolveType());
}
resolveType() return me SomeDto.class
UPD. Solved.
Problem was in body, it's not only {"num":"5600511164","id":22}, it contains another info.
I am passing a request body to a POST request on postman similar to this:
"name":"Mars",
"artifacts":[
{
"elements":[
{
"name":"carbon",
"amount":0.5,
"measurement":"g"
}
],
"typeName":"typeA"
},
{
"elements":[
{
"name":"hydrogen",
"amount":0.2,
"measurement":"g"
}
],
"typeName":"typeB"
}
]
The create method in the rest controller looks like this.
#RequestMapping("/create")
public Planet create(#RequestBody Planet data) {
Planet mars = planetService.create(data.getName(),data.getArtifacts());
return mars;
Planet and all its nested objects have a default constructor such as:
public Planet() {}
However, I am not able to create a new planet object because of lack of a default constructor. Please help!
EDIT:
Planet class
public class Planet {
#JsonProperty("name")
private String name;
#Field("artifacts")
private List<Artifact> artifacts;
public Planet() {}
public Planet(String name, List<Artifact> artifacts)
{
this.name = name;
this.artifacts = artifacts;
}
//setters and getters
}
Artifact class:
public class Artifact() {
#Field("elements")
private List<Element> elements;
#JsonProperty("typeName")
private String typeName;
public Artifact() {}
public Artifact(String typeName, List<Element> elements)
{
this.typeName = typeName;
this.elements = elements;
}
}
Element class:
public class Element() {
#JsonProperty("elementName")
private String name;
#JsonProperty("amount")
private double amount;
#JsonProperty("measurement")
private String measurement;
public Element() {}
public Element(String name, double amount, String measurement)
{
//assignments
}
}
I had that the same error when I forgot the #RequestBody before the parameter
#RequestMapping("/create")
public Planet create(#RequestBody Planet data) {
I don't understand what is the issue you are facing, but i can see an error straight away so guessing that is the issue you are facing, i am going to give you a solution.
Create a class which matches your json data structure like this :
Class PlanetData {
private String name;
private List<Planet> artifacts;
public PlanetData(String name, List<Planet> artifacts){
name = name;
artifacts = artifacts;
}
// include rest of getters and setters here.
}
Then your controller should look like this. Basically you needed to put #RequestBody to all the parameters you want to recieve from request JSON. Earlier you only put #RequestBody to name parameter not artifact parameter and since Request Body can be consumed only once, so you need a wrapper class to recieve the complete request body using single #RequestBody annotation.
#RequestMapping("/create")
public String create(#RequestBody PlanetData data) {
Planet mars = planetService.create(data.getName(),data.getArtifacts());
return mars.toString();
}
Edit : Looking at the Planet class, it also needs some modification
public class Planet {
private String typeName; // key in json should match variable name for proper deserialization or you need to use some jackson annotation to map your json key to your variable name.
private List<Element> elements;
public Planet() {}
public Planet(String typeName, List<Element> elements)
{
this.typeName = typeName;
this.elements = elements;
}
//setters and getters. Remember to change your setters and getter from name to typeName.
}
Hope this solves your issue.
This answer too might help someone.
When you are using spring framework for your API development, you may accidently import a wrong library for RequestBody and RequestHeader annotations.
In my case, I accidently imported library,
io.swagger.v3.oas.annotations.parameters.RequestBody
This could arise the above issue.
Please ensure that, you are using the correct library which is
org.springframework.web.bind.annotation.RequestBody
I guess, it’s trying to call new List() which has no constructor. Try using ArrayList in your signatures.
If it works this way, you have found the error. Then rethink your concept of calling methods, since you would usually want to avoid using implementations of List in method signatures
Make sure your request type is not of type GET
If so it is better not to send data as request body.
you should write as below:
...
public String create(#RequestBody JSONObject requestParams) {
String name=requestParams.getString("name");
List<Planet> planetArtifacts=requestParams.getJSONArray("artifacts").toJavaList(Planet.Class);
...
I have to deserialize my Java Object and I can't use static reference i.e TypeReference.
Like,
mentioned in here
So, I am left with is generating the right Javatype using type factory, but somehow I am not able to get the syntax right.
Aforementioned are my Classes and Interfaces.
public interface Request {}
public interface Response {}
public class MyRequest implements Request {
int id;
//Getter //Setter
}
public class MyResponse implements Response {
int id;
//Getter //Setter
}
public class UberObject<S extends Request, T extends Response> implements Serializable {
private S request;
private T response;
//Getter//Setter
}
public class UberObjectWithId<S extends Request, T extends Response> extends UberObject<S, T> {
private int id;
//Getter //Setter
}
UberObjectWithId typereferencedObject =
objectmapperobject.readValue(serialisedUberObjectWithId,
new TypeReference<UberObjectWithId<MyRequest, MyResponse>>() {});
The above approach works but I can't use TypeReference because of the limitation mentioned in the above link.
I tried using the Typefactory to retrieve the JavaType but I am not able to get the syntax right.
JavaType type = mapper.getTypeFactory().constructParametrizedType(UberObjectWithId.class,
UberObject.class, Request.class, Response.class);
but the call fails
objectmapperobject.readValue(serialisedUberObjectWithId, type);
How can I resolve my particular problem?
I fixed it by using the correct syntax to generate the JavaType
JavaType type = mapper.getTypeFactory().constructParametrizedType(UberObjectWithId.class,
UberObject.class, MyRequest.class, MyResponse.class);
It requires concrete classes while deserializing.
How to i can discriminate command objects in spring-mvc Controller? For example, i have following bean-classes used as form object:
public class CreateServiceFormBean {
#NotBlank
#Length(min = 3, max = 120)
private String name;
}
public class CreateDependedServiceFormBean extends CreateServiceFormBean {
#NotNull
private Short parentServiceId;
}
Getter's and Setter's is cutted out.
#RequestMapping(method = RequestMethod.POST)
public String createService(CreateServiceFormBean form) {
if (form instanceof CreateServiceFormBean) {
System.out.println("create Service");
//new ServiceEntity(form.getName())
} else if (form instanceof CreateDependedServiceFormBean) {
System.out.println("create depended Service");
parentService = ... get parent service entity...
//new DependedServiceEntity(form.getName(), parentService)
}
return null;
}
How do this? I think about create abstract controller for this two dto's, but is not elegant..maybe can handled in one method..
And how to correct get parent service entity? Some like method ModelAttribute annotation whose return entity by id?
Thanks for Replies!