Duplicate Values while using ObjectMapper of Jackson - java

My Bean class is as below. When the mapping happens, the JSON object contains duplicate values.
Response:
{"Id":"00PJ0000003mOgMMAU","Name":"web.xml","name":"web.xml","id":"00PJ0000003mOgMMAU"}
Why the values are getting duplicated?
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
#JsonIgnoreProperties(ignoreUnknown = true)
public class AttachmentsMapper
{
#JsonProperty(value = "Id")
private String Id;
#JsonProperty(value = "Name")
private String Name;
public String getId() {
return Id;
}
public void setId(String Id) {
this.Id = Id;
}
public String getName() {
return Name;
}
public void setName(String Name) {
this.Name = Name;
}
}

It doesn't print duplicate the same field twice it prints 2 different fields that it finds. Jackson sees you want to print "name" because you have a getter called getName() and "Name" because you have annotated the Name field as #JsonProperty with a different key. It sees different fields because "name" != "Name". Two solutions :
Move the annotation to the getter. The field is ignored by default because it's private E.g.
#JsonProperty(value = "Name")
public String getName() {
return Name;
}
Use a more recent version of Jackson as you seem to be using 1.8 from com.codehaus. Use 1.9 from there or even better use the latest from com.fasterxml. I tried your code as it is with 1.9 and it worked without moving the annotation.

In Jackson 2 try to disable Jackson visibility for all the sources (getters, setters, fields, etc.) and then just enable the visibility for the object fields:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
...
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

Related

Unable to map a JSON field with Hyphen to the Java Object field

The Java POJO is like this:
import javax.validation.Valid;
import com.fasterxml.jackson.annotation.JsonProperty;
Class MyClass{
#JsonProperty(value = "config-meta-info")
#Valid
private ConfigMetaInformation configMetaInfo;
#JsonProperty(value = "name")
#Valid
private String name;
public MyClass(){}
public MyClass(String name,ConfigMetaInformation configMetaInfo){
this.name=name;
this.configMetaInfo=configMetaInfo;
}
#JsonProperty("name")
public String getName() {
return name;
}
#JsonProperty("name")
public void setName(String name) {
this.name = name;
}
#JsonProperty("config-meta-info")
public ConfigMetaInformation getConfigMetaInfo() {
return configMetaInfo;
}
#JsonProperty("config-meta-info")
public void setConfigMetaInfo(ConfigMetaInformation configMetaInfo) {
this.configMetaInfo= configMetaInfo;
}
}
I am Using the JSON as below:
{
"name":"abc",
"config-meta-info":"someInfo"
}
But when I try to get the Data from the MongoDB document , I am seeing the config-meta-info as null.
Am I missing anything to handle this kebab-case key?
I could be wrong in the case of MongoDB but in other JSON based databases, they don't allow hyphenation in the field/key, underscores are usually preferred. Instead of config-meta-info, try config_meta_info.
The structure which you showed:
{
name:"abc",
config-meta-info:"someInfo"
}
is not a JSON.
Specification RFC-8259 defines all types (6) but what is name or config-meta-info? It can be JavaScript, but not a JSON.
The proper JSON:
{
"name":"abc",
"config-meta-info":"someInfo"
}
And you can use hyphen without limitations.

Rename columns in spark using #JsonProperty while creating Datasets

Is there way to rename the column names in dataset using Jackson annotations while creating a Dataset?
My encoder class is as follows:
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import scala.Serializable;
import javax.persistence.Table;
#Builder
#Data
#AllArgsConstructor
#EqualsAndHashCode
#Table(name = "sample_table")
public class SampleRecord implements Serializable {
#JsonProperty("sample_id")
private Long sampleId;
#JsonProperty("sample_name")
private String name;
#JsonProperty("sample_desc")
private String description;
}
My aim is to rename the columns according to the #JsonProperty, so that I can re-use the same class and json functionality.
Please find related versions of modules:
- Spark : 2.4.0 (with scala 2.11)
- jackson-module-scala_2.11 : 2.9.6
Let me know if you need more information. Help appreciated.
public class SampleRecord implements Serializable {
private Long sampleId;
private String name;
private String description;
#JsonProperty("sample_id")
public void setSampleId(Long sampleId) {
this.sampleId = sampleId;
}
#JsonProperty("sample_name")
public void setName(String name) {
this.name = name;
}
#JsonProperty("sample_desc")
public void setDescription(String description) {
this.description = description;
}
}
Interesting idea. The way I would do it:
Ingest your data in a dataframe.
Write a utility method that takes the dataframe and class name (here SampleRecord).
Use introspection to read the annotations (you could eventually add some if you need to define specific properties).
Rename the columns with withColumnRenamed() on the dataframe.
Return the modified dataframe.
hih

How to hide some the fields of an object that are being mapped to JSON by Jackson and #JsonIgnore fails

I need to hide some of the fields in the model class in my response object.
I tried to follow this SO answer
but with no luck.
when there are getter and setters for a field then the #JsonIgnore annotation doesn't seem to be working. see the following code snippet for clarifications.
#ApiModel(description = "")
public class APIInfoDTO {
private String id = null;
#JsonIgnore //this field will not be hidden when getters and setters are defined..
private String name = null;
private String status = null;
#JsonIgnore // this "info" field is hidden since there are no getters and setters for this field
private String info = "adncusdvshbdvsbvhdb";
/**
**/
#ApiModelProperty(value = "")
#JsonProperty("id")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
/**
**/
#ApiModelProperty(value = "")
#JsonProperty("name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
**/
#ApiModelProperty(value = "")
#JsonIgnore
public String getDescription() {
return description;
}
#JsonProperty("description")
public void setDescription(String description) {
this.description = description;
}
furthermore this is the code snippet for object mapping
public static APIInfoDTO fromAPIToInfoDTO(API api) {
APIInfoDTO apiInfoDTO = new APIInfoDTO();
apiInfoDTO.setDescription(api.getDescription());
apiInfoDTO.setContext(api.getContext());
apiInfoDTO.setId(api.getUUID());
APIIdentifier apiId = api.getId();
apiInfoDTO.setName(apiId.getApiName());
apiInfoDTO.setVersion(apiId.getVersion());
apiInfoDTO.setProvider(apiId.getProviderName());
apiInfoDTO.setStatus(api.getStatus().toString());
String providerName = api.getId().getProviderName();
apiInfoDTO.setProvider(APIUtil.replaceEmailDomainBack(providerName));
return apiInfoDTO;
}
any helpful answer would be highly appreciated.. Thanks
[UPDATE] The #JsonIgnore works with org.codehaus.jackson:jackson-core-asl:1.8.6 but fails with com.fasterxml.jackson.core:jackson-annotations:2.7.2.. Any idea why???
Add #JsonIgnore Annotation to the getter method as well.
Or Try adding #JsonIgnoreProperties(value={"name"}) at Class level, if this is an option for you
UPDATE
If you have Proper Jackson Library in your classpath (group: 'com.fasterxml.jackson.core', name: 'jackson-core'), #JsonIgnore on your field will work just fine; as long as the getter method you have is a standard getter, you don't have to annotate getter with #JsonIgnore.
If you want to serialize and deserialize your object based only on fields annotations, the Jackson ObjectMapper should be configured to ignore getters and setters method:
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibilityChecker(mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE));
or
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
It can also be configured at Class level using the #JsonAutoDetect annotation.
#JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
public class APIInfoDTO {
// ...
}

Object properties lowercased when reading as JSONObject

I have the following problem. I'm reading a list of records from my MySQL database with Hibernate template, and then I need to modify the structure so I'm JSONObject and JSONArray (using I guess the official library : http://www.json.org/java/). If I'm using the List as a server response, records fields are properly named (thanks to #JsonProperty annotation used). But if I'm trying to create a JSONObject out of this List element, I'm getting all my fields starting with small letter, which breaks my UI.
This is my 'Task' model used :
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
#JsonAutoDetect
#JsonIgnoreProperties(ignoreUnknown = true)
#Entity
#Table(name="tasks")
public class Task {
#Id
#GeneratedValue
#Column(name="Id")
private int Id;
#Column(name="Name", nullable=false)
private String Name;
#JsonProperty("Id")
public int getId() {
return Id;
}
#JsonProperty("Id")
public void setId(int id) {
this.Id = id;
}
#JsonProperty("Name")
public String getName() {
return Name;
}
#JsonProperty("Name")
public void setName(String name) {
this.Name = name;
}
}
and here's the code used for getting records from the DB (stripped of all the unnecessary parts):
public List<Task> getEvents() {
DetachedCriteria criteria = DetachedCriteria.forClass(Task.class);
return hibernateTemplate.findByCriteria(criteria);
}
private static JSONArray read() throws JSONException{
List<Task> list = getEvents();
Iterator<Task> listIterator = list.iterator();
JSONArray ret = new JSONArray();
String parentId;
while(listIterator.hasNext()){
Task task = listIterator.next();
JSONObject taskJSON = new JSONObject(task);
ret.put(taskJSON);
}
}
As you can see in my server response, all fields names start with small letter :
{"id":18,"name":"Release"}
Any ideas how to override this ?
Your class is overannotated, and breaks Java code conventions.
The minimum required is as follows. Everything else you've added is done by default.
#Entity
#Table(name="tasks")
public class Task {
#Id
#GeneratedValue
#Column(name="Id")
#JsonProperty("Id")
private int id;
#Column(name="Name", nullable=false)
#JsonProperty("Name")
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
To serialise your class all you should need is the ObjectMapper class
String json = new ObjectMapper().writeValueAsString(getEvents());
The output of which should look like:
[{"Id":18,"Name":"Build"}, {"Id":19,"Name":"Release"}]
I would discourage using capitalised property names if possible as it goes against general code conventions.
The JSON.org API is intended for very simple serialization/deserialization, it can't do what your looking for. Having said that, the majority of your annotations are actually from Jackson, which can do what your trying to accomplish.
You already have the POJOs properly annotated for Jackson, so return a JSON string conforming to them, serialize using an ObjectMapper:
final List<Task> list = getEvents();
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(list);

Duplicate json property when converting java object to json string using jackson

I have Pojo object, with getAsJson function to return Json string for this object.
I use JsonProperty to define json properties in this object.
Use writeValueAsString of ObjectMapper to write json string for this object.
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
#JsonIgnoreProperties(ignoreUnknown=true)
public class LogLikeArticleDetail extends BaseObject {
private static final long serialVersionUID = -2018373118257019033L;
#JsonProperty("LikeArticleGUId")
private String likeArticleGUId;
#JsonProperty("UserId")
private String userID;
#JsonProperty("UserName")
private String userName;
#JsonProperty("IP")
private String ip;
#JsonProperty("OS")
private String os;
#JsonProperty("UserAgent")
private String userAgent;
#JsonProperty("WebsiteCode")
private String websiteCode;
#JsonProperty("ArticleId")
private String articleID;
#JsonProperty("ATitle")
private String aTitle;
#JsonProperty("CateAlias")
private String cateAlias;
#JsonProperty("LikeStatus")
private String likeStatus;
#JsonProperty("TimeStamp")
private Date timeStamp;
//get, set....
//....
#JsonIgnore
public String getAsJSON() throws JsonGenerationException, JsonMappingException, IOException{
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(this) ;
}
}
Now, i get result
public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
Calendar calendar = Calendar.getInstance();
LogLikeArticleDetail logLikeArticle = new LogLikeArticleDetail("1","2","3","4","5","6","7","8","what thing \"nothing\" show","10","11",calendar.getTime());
System.out.println(logLikeArticle.getAsJSON());
}
But the result's duplicated properties:
{"LikeArticleGUId":"1","UserId":"2","UserName":"3","IP":"4","OS":"5","UserAgent":"6","WebsiteCode":"7","ArticleId":"8","ATitle":"what thing \"nothing\" show","CateAlias":"10","LikeStatus":"11","TimeStamp":1352256727062,"_likeArticleGUId":"1","websiteCode":"7","likeStatus":"11","userID":"2","userName":"3","ip":"4","os":"5","userAgent":"6","articleID":"8","aTitle":"what thing \"nothing\" show","cateAlias":"10","timeStamp":1352256727062}
Show me what's occur in this problem ?
So i do follow:
how to specify jackson to only use fields - preferably globally
I add
#JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
before
public class LogLikeArticleDetail extends BaseObject
and the result that i want.
So can another solve that in getAsJson() function like:
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibilityChecker(mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
return mapper.writeValueAsString(this) ;
Thanks for #Sean Carpenter 's question and #kmb385 answer in link above.
You can also do this per POJO using annotations. Add this string to the top of your class you'd like no auto detection on:
#JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY,
getterVisibility=JsonAutoDetect.Visibility.NONE,
setterVisibility=JsonAutoDetect.Visibility.NONE,
creatorVisibility=JsonAutoDetect.Visibility.NONE)
For example:
#JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY, getterVisibility=JsonAutoDetect.Visibility.NONE,
setterVisibility=JsonAutoDetect.Visibility.NONE, creatorVisibility=JsonAutoDetect.Visibility.NONE)
class Play {
#JsonProperty("Name")
private String name;
#JsonProperty("NickName")
private String nickName;
public Play(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
}
This will return the properties I've defined and not auto-detect the field names and add them to my returned JSON result.
We can also use the #JsonProperty("Name") annotation directly on the getters to avoid duplication.
It is actually not an issue. So, over here what happened was Jackson library was unable to match those fields automatically (there is no assumption of case unification), so you end up with twice the properties you expect.
The simple fix for this issue is to just add annotations to either getters/setters (either is fine.)
#JsonProperty("UserName")
public String getUserName() {
return this.userName;
}
This issue was also raised in Jackson Github repo. You can find the answer in the following link.
https://github.com/FasterXML/jackson-databind/issues/1609

Categories

Resources