Right annotations to a list<String> JAXB - java

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.

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());

Selectively #JsonIgnore Immutables accessor methods, ONLY during serialization or deserialization using Jackson

This is definitely not a duplicate of Only using #JsonIgnore during serialization, but not deserialization. The problem is the same but in the context of Immutables.
When a model(DTO/DAO) is decorated as an Immutable, I am not able to selectively #JsonIgnore one of the properties during serialization. Suppose that we have a UserDto which is defined as an Immutable as follow
#Value.Immutable
#Value.Style(defaults = #Value.Immutable(copy = false), init = "set*")
#JsonSerialize(as = ImmutableUserDto.class)
#JsonDeserialize(builder = ImmutableUserDto.Builder.class)
public abstract class UserDto {
#JsonProperty("id")
#Value.Default
public int getId() {
return 0;
}
#JsonProperty("username")
public abstract String getUsername();
#JsonProperty("email")
public abstract String getEmail();
#JsonProperty("password")
public abstract String getPassword();
}
I believe it is fair to expect that during serialization we would want to ignore the password from the response of the service.
Without using Immutables if we were working with a simple class, then there are many ways to accomplish this. For example - annotate only the getter with #JsonIgnore. Or if possible define a different accessor method (something that doesn't have the get prefix) and only define the regular setter method... and so on.
If I try the same on the Immutables accessor method for the password as shown below:
#Value.Immutable
#Value.Style(defaults = #Value.Immutable(copy = false), init = "set*")
#JsonSersonIgnoreialize(as = ImmutableUserDto.class)
#JsonDeserialize(builder = ImmutableUserDto.Builder.class)
public abstract class UserDto {
....
#JsonProperty("password")
#JsonIgnore
public abstract String getPassword();
}
then, the generated ImmutableUserDto adds the #JsonIgnore on both the getter and setter as shown below.
#Generated(from = "UserDto", generator = "Immutables")
#SuppressWarnings({"all"})
#ParametersAreNonnullByDefault
#javax.annotation.Generated("org.immutables.processor.ProxyProcessor")
#Immutable
#CheckReturnValue
public final class ImmutableUserDto extends UserDto {
...
...
private final String password;
...
...
/**
* #return The value of the {#code password} attribute
*/
#JsonProperty("password")
#JsonIgnore
#Override
public String getPassword() {
return password;
}
...
...
...
#Generated(from = "UserDto", generator = "Immutables")
#NotThreadSafe
public static final class Builder {
...
...
private String password;
#JsonProperty("password")
#JsonIgnore
public final Builder setPassword(String password) {
this.password = password;
return this;
}
}
}
Serialization will work as expected. The password attribute will be excluded from the JSON. But when I try to de-serialize, I get the following error:
java.lang.IllegalStateException: Cannot build UserDto, some of the required attributes are not set [password]
Which is obvious as Immutables added the #JsonIgnore to the setter as well.
The documentation isn't of much help. In their Things to be aware of section, it just mentions the following regarding #JsonIgnore
If using #JsonIgnore, you should explicitly make an attribute
non-mandatory. In Immutables, an attribute can be declared as
non-mandatory via #Nullable, Optional or #Value.Default which are all
different in their effect and we do not derive anything automatically.
Using #Nullable or Optional or #Value.Default is not of any use in case of fields like password.
I have gone through the issue list on their GitHub page and there is a similar issue but the user was asking for a slightly different use case and using #Nullable could solve the problem which doesn't work in my case.
I have also tried to use one of the answers here. Still resulted in the same error.
It looked like this is not supported by Immutables library. I have created a new issue myself. Once I get some feedback from users on SOF, I will probably create a sscce.
I had to use the suggestion given by #benarena in this comment. However I had to explicitly specify the value attribute of the property along with the Access attribute.
#JsonProperty(value = "password", access = JsonProperty.Access.WRITE_ONLY) solved the problem.
The Immutable class would look like:
#Value.Immutable
#Value.Style(defaults = #Value.Immutable(copy = false), init = "set*")
#JsonSersonIgnoreialize(as = ImmutableUserDto.class)
#JsonDeserialize(builder = ImmutableUserDto.Builder.class)
public abstract class UserDto {
....
#JsonProperty(value = "password", access = JsonProperty.Access.WRITE_ONLY)
public abstract String getPassword();
}

JAXB - Controlling element names for lists inside wrapper class

I have a class wrapping up a list and some other attribute and in another class I have multiple instances of the wrapper type. I know that we can control the name of elements by adding XmlElement annotation to whichever element we need. Is there any way to specify the element name corresponding to the contents of a wrapper type from wherever the wrapper type is used?
For instance, the wrapper class looks like
#XmlAccessorType(XmlAccessType.FIELD)
public class Wrapper {
#XmlElement(name = "name")
private List<String> names;
private String comment;
//Getters and setters
}
And the wrapper is used as
private Wrapper employeeNames;
private Wrapper departmentNames;
private Wrapper someOtherNames;
Can I in someway annotate these fields, so that I would have XML formed as
<employeeNames>
<employeeName>ABC DEF</employeeName>
<employeeName>PQR STU</employeeName>
<employeeName>ABC</employeeName>
</employeeNames>
<departmentNames>
<departmentName>PQR</departmentName>
<departmentName>PQR STU</departmentName>
<departmentName>MNO</departmentName>
</departmentNames>
I know that if don't have the wrapper and directly use the lists, I can have #XmlElementWrapper and #XmlElement annotations used to build the XML like this.
You could try this:
#XmlAccessorType(XmlAccessType.FIELD)
public class Wrapper {
#XmlElements({
#XmlElement(name = "employeeName", type = EmployeeName.class),
#XmlElement(name = "departmentName", type = DepartmentName.class),
})
private List<Name> names;
private String comment;
public void setNames(List<Name> names) {
this.names = names;
}
}
and then EmployeeName and DepartmentName something like this:
#XmlAccessorType(XmlAccessType.FIELD)
public class EmployeeName implements Name {
#XmlValue
private String name;
public EmployeeName(String name) {
this.name = name;
}
}
They both implement an interface that doesn't do much:
public interface Name { }
I changed your List<String> to List<Name> in your wrapper, because the marshaling would have problem to differentiate between employeeName and departmentName if they both were of type String.
The only thing that comes to mind is that instead of #XmlElement you could use #XmlElementRef like
#XmlElementRef(name = "name")
private List<JAXBElement<String>> names;
Then you could specify the desired element name in each of the elements of names:
wrapper.names.add(new QName("departmentName"), String.class, "PQR");

JAX-B handling double nested elements from xml

Basically im trying to unmarhall this
<polls xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="polls.xsd">
<poll id="1">
<title>WSD Meeting</title>
<state>Open</state>
<userID>1</userID>
<datecreated>88/88/1996</datecreated>
<location>UTS</location>
<description>Meeting for assignment</description>
<meetings>
<meeting option ='1'>
<time>12:00</time>
<date>99/88/1996</date>
<responses>
<response>John Doe</response>
</responses>
</meeting>
<meeting option ='2'>
<time>12:00</time>
<date>99/88/1996</date>
<responses>
<response>John Doe</response>
<response>John Smith</response>
</responses>
</meeting>
</meetings>
</poll>
</polls>
and the unmarshalling hits trouble when I get to the Meetings
this is the Poll class
#XmlAccessorType(XmlAccessType.FIELD)
public class Poll implements Serializable {
#XmlAttribute
private int ID;
private String title;
private int state;
private int userID;
private String datecreated;
private String location;
private String description;
#XmlElement(name = "meetings")
private ArrayList<Meeting> meetings = new ArrayList<Meeting>();
and this is the meeting class
#XmlAccessorType(XmlAccessType.FIELD)
public class Meeting implements Serializable {
#XmlAttribute
private int option;
private String time;
private String date;
#XmlElement(name = "responses")
private ArrayList<Response> responses = new ArrayList<Response>();
basically the data from poll is getting marshalled in fine (i have checked this) but once it hits meetings it makes the list with one entry that is empty am i missing something?
You seem to be missing a Meetings class (corresponding to <meetings> )wrapping the Meeting instances (corresponding to <meeting>).
If you generated the JAXB using a tool like XJC this wouldn't have happened, so it's not clear how you ended up in this situation (maybe you were trying to customize something). But maybe this helps in any case.

Map XML with same element and attribute names to Java object

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.

Categories