Map XML with same element and attribute names to Java object - java

I already searched for this particular issue, the closest thread i found was this one: Java/JAXB: Unmarshall XML elements with same name but different attribute values to different class members But it's still not exactly what i need, so i hope someone can help me with this.
I am doing a SOAP request on a Zimbra Collaboration Suite 7 Server to get a contact. The response is something like this:
<cn fileAsStr="Arthur, Spooner" f="" id="280" rev="1973" d="1338524233000" t="" md="1338524233" ms="1973" l="7"><meta/><a n="homePostalCode">93849</a><a n="lastName">Spooner</a><a n="birthday">1980-05-24</a><a n="homeStreet">Berkleystreet 99</a><a n="firstName">Arthur</a></cn>
I want to map this to a Java object, something like this:
public class Contact {
Integer id;
Integer rev;
String namePrefix;
String firstName;
String middleName;
String lastName;
String jobTitle;
ArrayList<Adress> adresses;
Date birthday;
String department;
Integer mobilePhone;
String email;
String company;
String notes;
...
I usually do this using JAXB, but as all the elements are called a and all the attributes n, I don't know how to map this. I really would appreciate a code snippet or any kind of help. Thanks in advance.

You could try doing something like this:
#XmlAccessorType(XmlAccessType.FIELD)
public class ContactAttribute {
#XmlAttribute(name="n")
private String attribute;
#XmlValue
private String value;
}
#XmlRootElement(name = "cn")
#XmlAccessorType(XmlAccessType.FIELD)
public class Contact {
#XmlAttribute
Integer id;
#XmlAttribute
Integer rev;
//...
#XmlElements(#XmlElement(name = "a"))
List<ContactAttribute> attributes;
//...
}

Use the Castor Mapping
it will help you to Marshall and Unmarshall the data.

Related

How to create different JSON output for a complex object

I would like to generate different Json output for the same complex Java object depending on the use case.
For example check the following code:
class Employee {
private Long id;
private String name;
private EmployeeDetail detail;
private Department department;
...
}
class Department {
private Long id;
private String name;
private String address;
...
}
class EmployeeDetail {
private Long id;
private int salary;
private Date birthDate;
...
}
If I convert Employee to Json all of the fields from Employee, EmployeeDetail and Department will be present. And it is good for one use case.
However in the second use case I would like to skip Department details except the id field but keep the complete EmployeeDetail.
I know that I can add something similar #JsonView(EmployeeView.Basic.class) to the id field in the Department class and use Json views. However for cleaner code I would like to solve it inside the Employee class something like this:
class Employee {
private Long id;
private String name;
#JsonAllFields
private EmployeeDetail detail;
#JsonIdOnly
private Department department;
...
}
At the moment I use the Jackson library but can switch if required.
i think you can use com.fasterxml.jackson.annotation.
#JsonIgnore is used to ignore the logical property used in serialization and deserialization. #JsonIgnore can be used at setter, getter or field. You can use it in the fields in Department class except on ID. There are so many ways to do it. Either you can allow the only getter in serialization etc.
Example:
#JsonIgnore(false)
private String id;
OR
#JsonIgnoreProperties({ "bookName", "bookCategory" })
public class Book {
#JsonProperty("bookId")
private String id;
#JsonProperty("bookName")
private String name;
#JsonProperty("bookCategory")
private String category;
}
To know more about it, please refer: https://www.concretepage.com/jackson-api/jackson-jsonignore-jsonignoreproperties-and-jsonignoretype
I hope this helps.
Just found a solution using #JsonFilter
Now the Employee class looks like this:
class Employee {
private Long id;
private String name;
private EmployeeDetail detail;
#JsonFilter("departmentFilter")
private Department department;
...
}
And the code to generate the limited json looks like this:
ObjectMapper mapper = new ObjectMapper();
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.addFilter("departmentFilter", SimpleBeanPropertyFilter.filterOutAllExcept("id"));
mapper.setFilterProvider(filterProvider);
One small cons is that now I also need to define the filter to generate the full, detailed json like this:
filterProvider.addFilter("departmentFilter", SimpleBeanPropertyFilter.serializeAll());

Java Complex Object Replace

I never faced a requirement like that and I am pretty confused how can I implement that.
Lets consider the following Beans:
Company{
String companyName;
String companyId;
Person person;
//getter and setters
}
Person{
String id;
String name;
String lastName;
List<Address> address;
//getter and setters
}
Address{
String id;
String name;
String description;
//getter and setters
}
So the hierarchy would be like this:
Company has Person has Address
What I have to do is, replace all String fields with other String, for instance
Company.companyName = "Hi there #xyz"
Address.name = "St. Example #xyz"
I need to replace the char #xyx with #abcd, for instance.
The object is much more complex than that and has a huge hierarchy.
I tried to find some API that would help me to do that, however I couldn't find anyone (I don't know if look correctly).
A solution that I have is in each getter method replace the char, however I don't think that is the best way to solve that.
I appreciate your help.
Thanks in advance.
I could solve that using reflection. I did not find any API.

Right annotations to a list<String> JAXB

I searched and saw many questions with similiar scanerios yet i couldnt make my solution work
I want a simple object to be converted into XML using JAXB.
My problem is i have an arrayList as one of my properties and i just cant find the right annotation to go with it.
#XmlRootElement(name = "fighter")
public class fighter{
private int health;
private int energy;
private String name;
private List<String> abilities;
}
if i remove the abilities property i can marshall\unmarshall this class.
but when i try to do it with the abilities property its telling me i have illegal annotation
#XmlElementWrapper(name = "abilitiesList")
#XmlElement(name = "ability")
public List<String> getAbilities(){
return abilities
}
I've tried all sort of annotations but I just dont get whats wrong with it.
Thanks for the help
Try this :
#XmlRootElement(name = "fighter")
#XmlAccessorType(XmlAccessType.FIELD)
public class Fighter{
#XmlElement
private int health;
#XmlElement
private int energy;
#XmlElement
private String name;
#XmlElementWrapper(name = "abilitiesList")
#XmlElement(name = "ability")
private List<String> abilities;
}
Your getters and setters must be without JAXB annotations.
Your list of abilities will be marshalled like this :
<abilitiesList>
<ability></ability>
<ability></ability>
</abilitiesList>
If it's not working, please provide a sample of your expected XML.

Only using #JsonIgnore during serialization, but not deserialization

I have a user object that is sent to and from the server. When I send out the user object, I don't want to send the hashed password to the client. So, I added #JsonIgnore on the password property, but this also blocks it from being deserialized into the password that makes it hard to sign up users when they don't have a password.
How can I only get #JsonIgnore to apply to serialization and not deserialization? I'm using Spring JSONView, so I don't have a ton of control over the ObjectMapper.
Things I've tried:
Add #JsonIgnore to the property
Add #JsonIgnore on the getter method only
Exactly how to do this depends on the version of Jackson that you're using. This changed around version 1.9, before that, you could do this by adding #JsonIgnore to the getter.
Which you've tried:
Add #JsonIgnore on the getter method only
Do this, and also add a specific #JsonProperty annotation for your JSON "password" field name to the setter method for the password on your object.
More recent versions of Jackson have added READ_ONLY and WRITE_ONLY annotation arguments for JsonProperty. So you could also do something like:
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;
Docs can be found here.
In order to accomplish this, all that we need is two annotations:
#JsonIgnore
#JsonProperty
Use #JsonIgnore on the class member and its getter, and #JsonProperty on its setter. A sample illustration would help to do this:
class User {
// More fields here
#JsonIgnore
private String password;
#JsonIgnore
public String getPassword() {
return password;
}
#JsonProperty
public void setPassword(final String password) {
this.password = password;
}
}
Since version 2.6: a more intuitive way is to use the com.fasterxml.jackson.annotation.JsonProperty annotation on the field:
#JsonProperty(access = Access.WRITE_ONLY)
private String myField;
Even if a getter exists, the field value is excluded from serialization.
JavaDoc says:
/**
* Access setting that means that the property may only be written (set)
* for deserialization,
* but will not be read (get) on serialization, that is, the value of the property
* is not included in serialization.
*/
WRITE_ONLY
In case you need it the other way around, just use Access.READ_ONLY.
In my case, I have Jackson automatically (de)serializing objects that I return from a Spring MVC controller (I am using #RestController with Spring 4.1.6). I had to use com.fasterxml.jackson.annotation.JsonIgnore instead of org.codehaus.jackson.annotate.JsonIgnore, as otherwise, it simply did nothing.
Another easy way to handle this is to use the argument allowSetters=truein the annotation. This will allow the password to be deserialized into your dto but it will not serialize it into a response body that uses contains object.
example:
#JsonIgnoreProperties(allowSetters = true, value = {"bar"})
class Pojo{
String foo;
String bar;
}
Both foo and bar are populated in the object, but only foo is written into a response body.
"user": {
"firstName": "Musa",
"lastName": "Aliyev",
"email": "klaudi2012#gmail.com",
"passwordIn": "98989898", (or encoded version in front if we not using https)
"country": "Azeribaijan",
"phone": "+994707702747"
}
#CrossOrigin(methods=RequestMethod.POST)
#RequestMapping("/public/register")
public #ResponseBody MsgKit registerNewUsert(#RequestBody User u){
root.registerUser(u);
return new MsgKit("registered");
}
#Service
#Transactional
public class RootBsn {
#Autowired UserRepository userRepo;
public void registerUser(User u) throws Exception{
u.setPassword(u.getPasswordIn());
//Generate some salt and setPassword (encoded - salt+password)
User u=userRepo.save(u);
System.out.println("Registration information saved");
}
}
#Entity
#JsonIgnoreProperties({"recordDate","modificationDate","status","createdBy","modifiedBy","salt","password"})
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String country;
#Column(name="CREATED_BY")
private String createdBy;
private String email;
#Column(name="FIRST_NAME")
private String firstName;
#Column(name="LAST_LOGIN_DATE")
private Timestamp lastLoginDate;
#Column(name="LAST_NAME")
private String lastName;
#Column(name="MODIFICATION_DATE")
private Timestamp modificationDate;
#Column(name="MODIFIED_BY")
private String modifiedBy;
private String password;
#Transient
private String passwordIn;
private String phone;
#Column(name="RECORD_DATE")
private Timestamp recordDate;
private String salt;
private String status;
#Column(name="USER_STATUS")
private String userStatus;
public User() {
}
// getters and setters
}
You can use #JsonIgnoreProperties at class level and put variables you want to igonre in json in "value" parameter.Worked for me fine.
#JsonIgnoreProperties(value = { "myVariable1","myVariable2" })
public class MyClass {
private int myVariable1;,
private int myVariable2;
}
You can also do like:
#JsonIgnore
#JsonProperty(access = Access.WRITE_ONLY)
private String password;
It's worked for me
I was looking for something similar. I still wanted my property serialized but wanted to alter the value using a different getter. In the below example, I'm deserializing the real password but serializing to a masked password. Here's how to do it:
public class User() {
private static final String PASSWORD_MASK = "*********";
#JsonIgnore
private String password;
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
public String setPassword(String password) {
if (!password.equals(PASSWORD_MASK) {
this.password = password;
}
}
public String getPassword() {
return password;
}
#JsonProperty("password")
public String getPasswordMasked() {
return PASSWORD_MASK;
}
}
The ideal solution would be to use DTO (data transfer object)

How to change a field name in JSON using Jackson

I'm using jackson to convert an object of mine to json.
The object has 2 fields:
#Entity
public class City {
#id
Long id;
String name;
public String getName() { return name; }
public void setName(String name){ this.name = name; }
public Long getId() { return id; }
public void setName(Long id){ this.id = id; }
}
Since I want to use this with the jQuery auto complete feature I want 'id' to appear as 'value' in the json and 'name' to appear as 'label'. The documentation of jackson is not clear on this and I've tried every annotation that even remotely seems like it does what I need but I can't get name to appear as label and id to appear as value in the json.
Does anyone know how to do this or if this is possible?
Have you tried using #JsonProperty?
#Entity
public class City {
#id
Long id;
String name;
#JsonProperty("label")
public String getName() { return name; }
public void setName(String name){ this.name = name; }
#JsonProperty("value")
public Long getId() { return id; }
public void setId(Long id){ this.id = id; }
}
Be aware that there is org.codehaus.jackson.annotate.JsonProperty in Jackson 1.x and com.fasterxml.jackson.annotation.JsonProperty in Jackson 2.x. Check which ObjectMapper you are using (from which version), and make sure you use the proper annotation.
Jackson
If you are using Jackson, then you can use the #JsonProperty annotation to customize the name of a given JSON property.
Therefore, you just have to annotate the entity fields with the #JsonProperty annotation and provide a custom JSON property name, like this:
#Entity
public class City {
#Id
#JsonProperty("value")
private Long id;
#JsonProperty("label")
private String name;
//Getters and setters omitted for brevity
}
JavaEE or JakartaEE JSON-B
JSON-B is the standard binding layer for converting Java objects to and from JSON. If you are using JSON-B, then you can override the JSON property name via the #JsonbProperty annotation:
#Entity
public class City {
#Id
#JsonbProperty("value")
private Long id;
#JsonbProperty("label")
private String name;
//Getters and setters omitted for brevity
}
There is one more option to rename field:
Jackson MixIns.
Useful if you deal with third party classes, which you are not able to annotate, or you just do not want to pollute the class with Jackson specific annotations.
The Jackson documentation for Mixins is outdated, so this example can provide more clarity. In essence: you create mixin class which does the serialization in the way you want. Then register it to the ObjectMapper:
objectMapper.addMixIn(ThirdParty.class, MyMixIn.class);

Categories