Jackson not recognizing fields that exist - java

So here's my JSON
{"totalSize":46,"done":true,"records":[{"Name":"Wamu I","Start_Date__c":"2016-09-26T16:56:10.000+0000","Status__c":"Completed","Type__c":"Your were expecting success, but In reality it was I, Dio!!!"}]}
And here are my two entity classes:
#JsonIgnoreProperties(ignoreUnknown = true)
public class EsidesiJobEntity {
#JsonProperty("totalSize")
private #Getter #Setter Integer totalSize;
#JsonProperty("done")
private #Getter #Setter Boolean isDone;
#JsonProperty("records")
private #Getter #Setter List<KarsEntity> records;
#Override
#JsonIgnore
public String toString(){
List<String> recordsObjectString = new ArrayList<String>();
this.records.forEach((record) ->
{
recordsObjectString.add(record.toString());
});
return "{ totalSize:"+this.totalSize+", isDone:"+this.isDone+", records:["+recordsObjectString.toString()+"]";
}
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class KarsEntity {
#JsonProperty("Name")
private #Getter #Setter String name;
#JsonProperty("Start_Date__c")
private #Getter #Setter String startDate;
#JsonProperty("Status__c")
private #Getter #Setter String status;
#Override
public String toString(){
return "{ name:"+this.name+", startDate:"+this.startDate+", status:"+this.status+"}";
}
}
for some reason, when I map that json string to the EsidesiJobEntity, I get the following error:
Unrecognized field "totalSize"
BUT IT DEFINITELY EXISTS IN BOTH IN BOTH THE JSON AND THE ENTITY!
Here's the code I wrote to map the string to the entity for reference:
EsidesiEntity apexJobResponseEntity;
ObjectMapper apexMapper = new ObjectMapper();
try {
apexJobResponseEntity = apexMapper.readValue(apexResponseString, EsidesiEntity.class);
} ...
Am I missing something really basic?
(BTW, If there's some inconsistency in the Class/Entity names, its because I renamed them before posting them online. Let me know and I'll fix them as I see them. )
Thanks!

You are using Lombok. Jackson can't see your getter and setter methods.
So you have two options:
Do not use Lombok and implement the getter and setter methods
Use Lombok with this additional library: jackson-lombok
If you are using maven, so add jackson-lombok to your pom.xml:
<dependency>
<groupId>com.xebia</groupId>
<artifactId>jackson-lombok</artifactId>
<version>1.1</version>
</dependency>
Configure then your ObjectMapper in this way:
ObjectMapper apexMapper = new ObjectMapper();
apexMapper.setAnnotationIntrospector(new JacksonLombokAnnotationIntrospector());
[...]

Try this:
Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(youJson);
MyPojo pojo = gson.fromJson(jsonElement, MyPojo.class);

Related

Why is Jackson using the wrong element name when serializing?

I have a Object that I would like Jackson to serialize like this...
<AccountsResponse>
<accounts>
<account/>
<account>
<userId>user</userId>
...
</account>
</accounts>
</AccountsResponse>
To try this I create the following class...
#Getter
#Setter
#ToString
#JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Payload {
#JacksonXmlProperty(localName = "errormessage")
private String errorMessage;
}
#Getter
#Setter
#ToString
public class AccountsResponse extends Payload{
#JsonIgnore
private static Logger LOGGER = LogManager.getLogger(AccountsResponse.class);
#JacksonXmlProperty(localName = "accounts")
private List<Account> accounts = Lists.newArrayList();
public static AccountsResponse mapFromResultSet(ResultSet rs)
throws SQLException
{
AccountsResponse response = new AccountsResponse();
do {
Account acct = Account.mapFromResultSet(rs);
response.getAccounts().add(acct);
} while (rs.next());
return response;
}
public String toXml() throws JsonProcessingException {
ObjectMapper mapper = new XmlMapper();
return mapper.writeValueAsString(this);
}
}
#Getter
#Setter
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Account extends ResultSetParser{
...
}
But when I serialize I get...
<AccountsResponse>
<accounts>
<accounts/>
<accounts>
<userId>user</userId>
...
</accounts>
</accounts>
</AccountsResponse>
As you can see the problem here is the child tags should be account but in fact are accounts. I tried hacking around with the localname but can't find the right mixture of VooDoo. What am I doing wrong?
I would change annotations on account list in AccountsResponse:
public class AccountsResponse extends Payload{
#JacksonXmlElementWrapper(localName = "accounts")
#JacksonXmlProperty(localName = "account")
private List<Account> accounts = Lists.newArrayList();
}

ModelMapper: Incorect property mapping from null objects

I'm trying to map source object which property is set to null to destination object of which this property is set to another object.
Expected result would be that property of destination object will be null after mapping. Instead of that, this property is set to an object and all of its properties are set to null.
Here is an example:
public class ModelMapperTest {
public static void main(String[] args) {
ModelMapper modelMapper = new ModelMapper();
User user = new User();
user.setStatus(null);
StatusDto statusDto = new StatusDto();
statusDto.setId(1);
statusDto.setName("Active");
UserDto userDto = new UserDto();
userDto.setStatus(statusDto);
// user.status=null, userDto.status=StatusDto(id=1, name="Active")
modelMapper.map(user, userDto);
System.out.println("user = " + user);
System.out.println("userDto = " + userDto);
}
#Getter
#Setter
#ToString
public static class User {
private Status status;
}
#Getter
#Setter
#ToString
public static class Status {
private Integer id;
private String name;
}
#Getter
#Setter
#ToString
public static class UserDto {
private StatusDto status;
}
#Getter
#Setter
#ToString
public static class StatusDto {
private Integer id;
private String name;
}
}
Output:
user = ModelMapperTest.User(status=null)
userDto = ModelMapperTest.UserDto(status=ModelMapperTest.StatusDto(id=null, name=null))
Is it possible to somehow configure model mapper to sets UserDto.status to null?
I know this is an older question and you seem to have moved on to a different library, but I had the same problem recently and came up with this solution (building on your example):
Converter<?, ?> preserveNullConverter = (context) ->
context.getSource() == null
? null
: modelMapper.map(context.getSource(), context.getDestinationType());
modelMapper.createTypeMap(User.class, UserDto.class)
.addMappings(mapper -> mapper.using(preserveNullConverter).map(User::getStatus, UserDto::setStatus));
It's not ideal because the .addMappings part needs to be done for every property where the issue occurs, but at least the Converter can be reused.

How to convert embedded JSON String inside JSON to java object?

I have the below json, where the body key contains a value which is a string representation of a JSON object, how do I convert it to a Java Object ?
I can extract the body value by converting the JSON to a Map, but I don't know how I should proceed from there
input.json file
{
"body": "{\n\t\"username\": \"TestUser\",\n\t\"password\": \"TestPassword\"\n}"
}
The User POJO is as below,
class User {
private String username;
private String password;
... getters, setters and no-arg constructor
}
My code looks something like this, I need to implement convertToUser function
public static void main(String[] args) {
String jsonContent = readJsonFile("input.json");
String escapedJsonBody = getBody(s);
User user = convertToUser(escapedJsonBody, User.class);
}
I am already using jackson java library, any insights on doing this with jackson is highly appreciated.
One way to do it is to create DTOs and converter. Having DTOs like (i have nested the class declarations jsut to save space in answer):
#Getter #Setter
public class Input { // this level maps to the whole input.json
#JsonDeserialize(using = BodyDeserializer.class) // custom deserializer below
private Body body; // this is the body-attribute in JSON
#Getter #Setter
public static class Body {
private User user;
#Getter #Setter
public static class User {
private String username;
private String password;
}
}
}
the converter:
public class BodyDeserializer extends JsonDeserializer<Body> {
private ObjectMapper om = new ObjectMapper(); // this is to read the user from string
#Override
public Body deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String embedded = p.readValueAs(String.class);
Body body = new Body();
body.setUser(om.readValue(embedded, User.class)); // here is the trick
return body;
}
}
Use like:
ObjectMapper om = new ObjectMapper();
String input = "{\"body\": \"{\\n\\t\\\"username\\\": \\\"TestUser\\\",\\n\\t\\\"password\\\": \\\"TestPassword\\\"\\n}\"}";
Input r = om.readValue(input, Input.class);
This way the conversion happens in generic way only con might be that you do not like to create DTOs and dig the user like Input.getBody().getUser();
To convert a JSON String to a java pojo you can use Jackson's ObjectMapper class that will assist you to do this.
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.readValue(inputJson, User.class);
More info can be found on Jackson's github page

Spring mapper with Java Map

I've been struggling with the following issue for a few hours now, and I can't figure it out how to make it work:
Spring mapper, in order to convert DB response to DTO:
#Mapper(componentModel = "spring")
public interface ITeamResponseToDtoMapper {
TeamResponseDTO toDto(TeamResponse teamResponse);
}
TeamResponse class:
#Data
#NoArgsConstructor
public class TeamResponse {
private Map<String, List<NameAndType>> teamList;
}
NameAndType class:
#Data
#NoArgsConstructor
#AllArgsConstructor(access = AccessLevel.PUBLIC)
public class NameAndType{
private String name;
private String type;
private String team;
}
TeamResponseDTO class:
#Data
#NoArgsConstructor
public class TeamResponseDTO {
private Map<String, List<NameAndTypeDTO >> teamList;
}
NameAndTypeDTO class:
#Data
#NoArgsConstructor
#AllArgsConstructor(access = AccessLevel.PUBLIC)
public class NameAndTypeDTO {
private String name;
private String type;
private String team;
}
Basically, 'NameAndType' and 'NameAndTypeDTO' are the same, why it fails to do the conversion?
error: Can't map property "java.util.Map<java.lang.String,java.util.List<com.microservices.teamservice.dataobjects.NameAndType>> teamList" to "java.util.Map<java.lang.String,java.util.List<com.microservices.teamservice.api.dataobjects.NameAndTypeDTO>> teamList". Consider to declare/implement a mapping method:
I think you need to explicit add methods to map the whole chain of classes. On your example the following should work:
#Mapper(componentModel = "spring")
public interface ITeamResponseToDtoMapper {
TeamResponseDTO toDto(TeamResponse teamResponse);
List<NameAndTypeDTO> natListToDTO(List<NameAndType> natList);
NameAndTypeDTO nameAndTypeToDTO(NameAndType nameAndType);
}
regards,
WiPu

Can not convert json to Model

I have json from url. I need Convert This json to Model
{
"someField": 3,
"datesField": ["2017-08-19",
"2017-08-20",
"2017-08-26",
"2018-12-30"]
}
I create models for mapping
#Data
#NoArgsConstructor
private class Response{
#JsonProperty("someField")
private int someField;
#JsonProperty("datesField")
private DatesField datesField;
}
#Data
#NoArgsConstructor
private class DatesField{
private String[] strings;
}
try convert
ObjectMapper mapper = new ObjectMapper();
Dates dates = mapper.readValue(forObject, Response.class);
I get error when try convert:
Can not deserialize instance of packeg.DatesField out of START_ARRAY
token
The json attributed is incorrect according to the model. There is no array of datesField type but an array of strings within the datesField object.
Your object json equivalent shall be:
{
"someField": 3,
"datesField": {
"strings":["2017-08-19",
"2017-08-20",
"2017-08-26",
"2018-12-30"]
}
}
Or the other way, if you need to adapt to the json response, change your model as suggested by #xenteros to:
#Data
#NoArgsConstructor
private class Response{
#JsonProperty("someField")
private int someField;
#JsonProperty("datesField")
private String[] datesField;
}
Also, note that the java code to map the response should be changed from:
Dates dates = mapper.readValue(forObject, Response.class);
to
Response response = mapper.readValue(forObject, Response.class);
{
"someField": 3,
"datesField": ["2017-08-19",
"2017-08-20",
"2017-08-26",
"2018-12-30"]
}
is equivalent to
#Data
#NoArgsConstructor
private class Response{
#JsonProperty("someField")
private int someField;
#JsonProperty("datesField")
private String[] datesField;
}
You should rather parse the following json:
{
"someField": 3,
"datesField": {
"strings":
["2017-08-19",
"2017-08-20",
"2017-08-26",
"2018-12-30"]
}
}

Categories