I'm using Jackson JSON LIB 2.8, and i'm using Json.mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES,true);
but sometimes I need to map some fields with two differents names like
POJO has attribute builindg and i need to map it to buildingUid or BUILDING depends on what key exist in JSON, are they any way to do this ?
Example :
public class Building extends Bean {
private UUID id;
private String name;
}
and I have two different sources , one is my Database which return a JSON with this format :
{
"ID":"build",
"NAME":"name1"
}
and my other source is a client :
{
"UID" : "build",
"name" : "name1"
}
As you can see my problem is to map id with both UID and ID , i manage to map the first one with :
Json.mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES,true);
but the other source is UID and i dont know how to map it automatically when i do something like
Json.encode(Building.toString());
It is possible using multiple setters annotated with #JsonSetter
Try something like this :
public class Building extends Bean {
private String id;
private String name;
#JsonGetter("id")
public String getId() {
return id;
}
#JsonSetter("id")
public void setId(String id) {
this.id = id;
}
#JsonSetter("UID")
public void setUID(String id) {
setId(id);
}
#JsonGetter("name")
public String getName() {
return name;
}
#JsonSetter("name")
public void setName(String name) {
this.name = name;
}
#JsonSetter("NAME")
public void setUpperCaseName(String name) {
setName(name);
}
}
But it's a little lousy (solution not dynamic).
Related
I have the following Java beans:
public class Customer implements Serializable {
private Integer id;
private String name;
private Country country;
public void setId(Integer id) {
this.id=id;
}
public void setName(String n) {
this.name=n;
}
public void setCountry(Country c) {
this.country=c;
}
public void setCountryId(Integer id) {
this.country= new Country();
this.country.setId(id)
}
//...getters here
}
and
public class Country {
private Integer id;
private String code; //es, us, fr...
private void setId(Integer id) {
this.id=id;
}
//rest of setters and getters
}
and I have the following method:
#RequestMapping(value = "/customer/", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<Customer> addSecondaryCustomer(#RequestBody Customer sc) {
this.customerService.addCustomer(sc);
return new ResponseEntity<>(sc,HttpStatus.OK);
}
Using the Web Development tools I can see the server is receiving the following:
{
"name": "Pablo Test",
"countryId": 1
}
I can see that the field name is populated, but country remains null. I've tried to set a breakpoint in both setters, but none of them is being called, so it seems that the object mapper is looking for attributes, ignoring setters. ¿Why is this happening?
I am using Jackson 2.9.0 and Spring 4.2.13. It worked with older versions of Spring (4.2.0) and Jackson (2.1.4)
PS: I know I can workaround this by sending "country": { "id": 1} in my AJAX request, but I need to know what's happening here.
How do you save a JSON Array as an item attribute? AWS documentation is the absolute worst thing ever - it contradicts itself, a lot of things are either redundant or only partially explained, some things aren't explained at all - I don't know how anyone manages to use it.
Anyway, suppose I have a table called Paths, and a path has a name, an ID, and a list of LatLngs (formatted as a JSON Array)
In the class definition for this table, I have
#DynamoDBTable(tableName = "Paths")
public class Path {
private String id;
private String name;
private JSONArray outlineJSON;
with getters and setters like
#DynamoDBRangeKey(attributeName = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
which works fine for strings, booleans and numbers, and the object saves successfully to the table.
AWS documentation mentions JSON several times, and says it can handle lists, but it doesn't explain how to use lists or give any examples.
I used #DynamoDBHashKey for the id, #DynamoDBRangeKey for name, and #DynamoDBAttribute for other strings, numbers or booleans, and I tried it here
#DynamoDBAttribute(attributeName = "outline")
private JSONArray getOutlineJSON() {
return outlineJSON;
}
private void setOutlineJSON(JSONArray outlineJSON) {
this.outlineJSON = outlineJSON;
}
It successfully saved the object but without the array.
How do I save the array? I can't find an explanation anywhere. I think #DynamoDBDocument might have something to do with it, but all the documentation on the subject gives unrelated examples, and I can't find any using a list like my in situation.
EDIT: For now, I have a working solution - I can easily convert my lists to JSONArrays and then convert those to Strings, and vice-versa.
You can define your class to be something like
#DynamoDBTable(tableName = "Paths")
public class Path {
private String id;
private String name;
private LatLang latLangs;
#DynamoDBHashKey(attributeName="id")
public String getId() { return id;}
public void setId(String id) {this.id = id;}
#DynamoDBRangeKey(attributeName = "name")
public String getName() { return name; }
public void setName(String name) { this.name = name; }
#DynamoDBDocument
public static class LatLang{
public String lat;
public String lang;
}
}
I am working with a web service that stores POJOs in a MongoDB. I want to make use of Mongo's 'expireAfterSeconds' time to live feature, to clear out old documents in my collection after a certain period of time.
Initially I had an implementation that sent the date to the REST service using the following JSON:
{
"testIndex": "testIndex",
"name": "hello",
"date": "2016-05-09T11:00:39.639Z"
}
The above code created the document in the collection, and with the following annotation, deleted the document after 10 seconds.
#Indexed (expireAfterSeconds=10)
private Date date;
After implementing this code, I decided I wanted to generate the date only on the Java side, meaning the JSON is now as follows:
{
"testIndex": "testIndex",
"name": "hello"
}
Then I have a constructor in the POJO using JsonCreator from Jackson
#JsonCreator
public TTLTestVO (#JsonProperty("testIndex") String testIndex, #JsonProperty("name") String name) {
this.testIndex = testIndex;
this.createdAt = new Date();
this.name = name;
}
From reading the documentation here I believe this should flag the constructor to be used when creating a new object. The testIndex and name fields are populated as before. However with this implementation, each time I check the document in my mongo the date value is 'null'. If I change the text for one of the string values to 'hello from the constructor', the constructor appears not to be called as the initial text contained in the JSON is what is added to the database.
POJO
`
#Document(collection = "test")public class TTLTestVO {
#Id private String _id;
#Indexed
private String testIndex;
#Indexed (expireAfterSeconds=10)
private Date createdAt;
private String name;
#JsonIgnore
public TTLTestVO() {
// default
}
#JsonCreator
public TTLTestVO (#JsonProperty("testIndex") String testIndex, #JsonProperty("name") String name) {
this.testIndex = "hello from the constructor";
this.name = 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;
}
public String getTestIndex() {
return testIndex;
}
public void setTestIndex(String testIndex) {
this.testIndex = testIndex;
}
public Date getDate() {
return createdAt;
}
public void setDate(Date date) {
this.createdAt = date;
}
`
After investigating some more I discovered the issue lies with the Spring Framework implementation of #JsonCreator - I removed the imports for org.springframework.cloud.cloudfoundry.com.fasterxml.jackson.annotation and replaced them with com.fasterxml.jackson.annotation. The above implementation now functions as expected.
I have been unable to find an explanation online as to why the spring version isn't working, so if anyone has any ideas please let me/ others know
I got json like below:
{"examinationTypes":[{"ExaminationTypeVO":{"id":1,"name":"Badanie krwi"}},{"ExaminationTypeVO":{"id":2,"name":"Spirometria"}},{"ExaminationTypeVO":{"id":3,"name":"Wymaz"}},{"ExaminationTypeVO":{"id":4,"name":"Ciśnienie"}},{"ExaminationTypeVO":{"id":5,"name":"EKG"}},{"ExaminationTypeVO":{"id":6,"name":"Elektrowstrząsy"}},{"ExaminationTypeVO":{"id":7,"name":"Tomografia"}},{"ExaminationTypeVO":{"id":8,"name":"Lewatywa"}},{"ExaminationTypeVO":{"id":9,"name":"Aneskopia"}},{"ExaminationTypeVO":{"id":10,"name":"Rektoskopia"}},{"ExaminationTypeVO":{"id":11,"name":"Kolonoskopioa"}},{"ExaminationTypeVO":{"id":12,"name":"Echo serca"}},{"ExaminationTypeVO":{"id":13,"name":"Ablacja"}},{"ExaminationTypeVO":{"id":14,"name":"Badnaie dopplerowskie"}},{"ExaminationTypeVO":{"id":15,"name":"Kapilaroskopia"}}]}
I have defined types:
#JsonRootName(value="ExaminationTypeVO")
#JsonIgnoreProperties(ignoreUnknown = true)
public class ExaminationTypeVO {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and
public class ExaminationTypesVO {
private List<ExaminationTypeVO> examinationTypes;
public List<ExaminationTypeVO> getExaminationTypes() {
return examinationTypes;
}
public void setExaminationTypes(List<ExaminationTypeVO> examinationTypes) {
this.examinationTypes = examinationTypes;
}
When I am deserializing it like that:
ExaminationTypesVO l = m.readValue(result, ExaminationTypesVO.class);
I receive an wrapper object but the list inside contains objects of type ExaminationTypeVO with all properties set to null.
Can anybody help to figure it out?
Your issue is that you have an extra level of object that you are trying to deserialize. Trying to not be confusing as I explain this: you have an array of objects, those objects contain a single ExaminationTypeVO object.
If you are stuck with the structure of the JSON that you provided, then you will need to add another "level" to your deserialization. You can do this via a wrapper object inside of your ExaminationTypesVO class:
public class ExaminationTypesVO {
private List<ExaminationTypeVOWrapper> examinationTypes;
public List<ExaminationTypeVOWrapper> getExaminationTypes() {
return examinationTypes;
}
public void setExaminationTypes(List<ExaminationTypeVOWrapper> examinationTypes) {
this.examinationTypes = examinationTypes;
}
public static class ExaminationTypeVOWrapper {
private final ExaminationTypeVO examinationTypeVO;
#JsonCreator
public ExaminationTypeVOWrapper(#JsonProperty("ExaminationTypeVO") ExaminationTypeVO examinationTypeVO) {
this.examinationTypeVO = examinationTypeVO;
}
public ExaminationTypeVO getExaminationTypeVO() {
return examinationTypeVO;
}
}
}
If you have control over the JSON that you are deserializing, you can just remove the extra "level" (ExaminationTypeVO wrapping object) and not have to change your code. Your new JSON in this approach would look like:
{
"examinationTypes": [
{
"id": 1,
"name": "Badanie krwi"
}, ...
]
}
With either of these approaches you can remove both of the class-level annotations you have on ExaminationTypeVO.
I am trying to serialize the below ArrayList of GAccount objects using Jackson library with following code:
List<Gaccount> gAccounts;
ObjectMapper mapper=new ObjectMapper();
json=mapper.writeValueAsString(gAccounts);
However, I have noticed that only Id and Name fields are serialized but not properties. Sorry, but I am new to Jackson library. Do I have to manually serialize that field ?
package in.co.madhur.ganalyticsdashclock;
import java.util.ArrayList;
import java.util.List;
public class GAccount
{
private String Id;
private String Name;
private List<GProperty> properties=new ArrayList<GProperty>();
public GAccount(String Id, String Name)
{
this.Id=Id;
this.Name=Name;
}
public String getName()
{
return Name;
}
public void setName(String name)
{
Name = name;
}
public String getId()
{
return Id;
}
public void setId(String id)
{
Id = id;
}
List<GProperty> getProperties()
{
return properties;
}
void setProperties(List<GProperty> properties)
{
this.properties = properties;
}
#Override
public String toString()
{
return Name;
}
}
The default visibility is to use all public getter methods and all public properties. If you make the getter this:
public List<GProperty> getProperties()
it should work.
You could also change the auto-detection defaults, but it's overkill here. See http://www.cowtowncoder.com/blog/archives/2011/02/entry_443.html for more info.
I am using jackson 2.9.0. The default visibility is always 'false' to all the members. In this case, we alway need to use a different visibility, otherwise the result json string will be empty. Here is the code extracted from JsonAutoDetect
public boolean isVisible(Member m) {
switch(this) {
case ANY:
return true;
...
case PUBLIC_ONLY:
return Modifier.isPublic(m.getModifiers());
default:
return false;
}
}