JAX-B handling double nested elements from xml - java

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.

Related

How to deserialize Json with a nested array of objects in a simple Spring Boot application

The Json POST request looks like this:
{
'title':'Star Wars: The Empire Strikes Back',
'description':'Darth Vader is adamant about turning Luke Skywalker to the dark side.',
'actors':[
{
'lastName':'Ford',
'name':'Harrison'
},
{
'lastName':'Hamill',
'name':'Mark'
}
]
}
So my Spring Boot Application just wants to store this whole json as a "Film" class and inside it has an inline array of "Actors". Here is the Film model:
#Entity
public class Film {
#Id
#GeneratedValue
private long id;
private String title;
private String description;
private ArrayList<Actor> actors = new ArrayList<>();
I have a separate entity for the Actor that looks similar:
#Entity
public class Actor {
#Id
#GeneratedValue
private long id;
private String name;
private String lastName;
Finally, I am using the RequestBody Annotation in the PostMapping in the Controller:
#PostMapping(value= "/api/film")
#ResponseStatus(HttpStatus.CREATED)
public Film addFilm(#RequestBody Film film) {
service.createFilm(film);
return film;
The problem is I always get the java.io.NotSerializableException that Actor cannot be serialized. I tried making Actor a Static inline class but that did not change anything. Anyone have an idea what is wrong here ?
Your Actor class needs to implement Serializable.
#Entity
public class Actor implements Serializable{
#Id
#GeneratedValue
private long id;
private String name;
private String lastName;

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

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.

Problems in mapping objects between the model and DTO

I am mapping between the following models:
#Entity
#Table(name="account_type")
#NamedQuery(name="AccountType.findAll", query="SELECT a FROM AccountType a")
public class AccountType implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="account_type_id")
private Integer accountTypeId;
#Column(name="account_type_code")
private String accountTypeCode;
#OneToMany(mappedBy="accountType")
private Set<Account> accounts;
Which has a set of Account:
#Entity
#NamedQuery(name="Account.findAll", query="SELECT a FROM Account a")
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="account_id")
private Integer accountId;
#Column(name="account_number")
private String accountNumber;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="account_type_id_fk")
private AccountType accountType;
And their DTOs.
I am having problems in mapping complex types like Account:
public static Account getAccount(AccountDTO dto) {
Account model = new Account();
model.setAccountId(dto.getAccountId());
model.setAccountNumber(dto.getAccountNumber());
model.setAccountType(dto.getAccountType());
// Error: can't convert from AccountypeDTO to AccountType
return model;
}
It gives an error that it can't convert from AccountypeDTO to AccountType
so I did the following:
model.setAccountType(getAccountType(dto.getAccountType()));
Where getAccountType method is:
public static AccountType getAccountType(AccountTypeDTO dto) {
AccountType model = new AccountType();
model.setAccountTypeId(dto.getAccountTypeId());
model.setAccountTypeCode(dto.getAccountTypeCode());
model.setAccounts(dto.getAccounts());
// Now here again a similar error
}
I think it's a deep recursive? How to solve this?
My question is how to convert them efficiently.
Annex
The code of acountTypeDTO:
#Component
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class AccountTypeDTO implements Serializable {
private static final long serialVersionUID = 1L;
#NotNull
#NotEmpty
private Integer accountTypeId;
#NotNull
#NotEmpty
private String accountTypeCode;
private Set<AccountDTO> accounts;
The code of AccountDTO:
#Component
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class AccountDTO implements Serializable {
private static final long serialVersionUID = 1L;
#NotNull
#NotEmpty
private Integer accountId;
#NotNull
#NotEmpty
private String accountNumber;
private AccountTypeDTO accountType;
Two alternative approaches jump to mind but they will require some change. I will preface this by saying that I have yet to be in a situation where converting to DTOs (even if I'm doing a deep recursive conversion) is the bottleneck. Even if your performance requirements or your scale were so large that it somehow did become a bottleneck then I would personally recommend dividing the work across multiple servers before I started to worry about performance down to that level of detail. Also, it may seem inefficient but performance is rarely intuitive, have you confirmed that this conversion is a bottleneck?
The first alternative is to not use separate classes as DTOs. Some approaches use the same class as the DTO and the underlying entities and some approaches use the DTO as the parent class and the entity class as the child class. This will save you from having to do any kind of DTO<->Entity conversion. There are drawbacks, as this almost always ends up combining two responsibilities into a single class and it can make your code more complex and less readable.
The second alternative is to not return the accounts themselves but instead to convert them to IDs. In this approach your AccountTypeDTO would have a Set<Integer> accountIds instead of a Set<AccountDTO> accounts. However, this only works if your client doesn't always need to operate on every account.

Class not persistence?

I'm trying to store in the GAE DB a class which some of its fields are classes themselves.
Just before going into more details I want to say it worked just fine before I added these new class field.
So, I followed the documentation here: https://developers.google.com/appengine/docs/java/datastore/jdo/dataclasses
and I'm getting this error :
org.datanucleus.jdo.exceptions.ClassNotPersistenceCapableException: The class "The class "sporteam.web.client.User" is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found." is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data for the class is not found.
The main class I'm trying to use is User:
#SuppressWarnings("serial")
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class User implements Serializable
{
// data members
// user unique facebook id
#Persistent
#PrimaryKey
private String facebook_id;
// users facebook code
#Persistent
private String facebook_code;
// users device ID code
#Persistent
private String dev_id;
// users registration ID code
#Persistent
private String reg_id;
// user first name
#Persistent
private String first_name;
// user last name
#Persistent
private String last_name;
// user age, should be grater then 8
#Persistent
private int age;
// user email, as setup in facebook
#Persistent
private String email;
// user weight, should be greater then 40
#Persistent
private double weight;
// user workout_level (0.8 is the highest(best shape) and 1 is the lowest)
#Persistent
private double workout_level;
// user gender ("male"/"female"/"unknown")
#Persistent
private String gender;
#Persistent
#Embedded
private UserTracks userTracks = null;
// default constructor
public User()
{
}
//....
}
This is the UserTracks class:
#PersistenceCapable
#EmbeddedOnly
#SuppressWarnings("serial")
public class UserTracks implements Serializable
{
#Persistent
#Embedded
//#Element(embedded="true")
private List<Track> tracks = null;
#Persistent
private long date = 0;
public UserTracks()
{
}
}
And theses are the other 2 classes used:
#PersistenceCapable
#EmbeddedOnly
#SuppressWarnings("serial")
public class Track implements Serializable
{
/** running information **/
#Persistent
private double avgSpeed = 0;
#Persistent
private double distance = 0;
#Persistent
private double calories = 0;
#Persistent
private long time = 0;
/************************/
#Persistent
private long date = 0;
#Persistent
private String name = null;
#Persistent
#Embedded
private List<GeoPtr> track = null;
public Track()
{ // needed for Serializable
}
}
GeoPtr:
#PersistenceCapable
#EmbeddedOnly
#SuppressWarnings("serial")
public class GeoPtr implements Serializable
{
/** the speed is in m/s **/
#Persistent
float speed;
#Persistent
long time;
#Persistent
double altitude;
#Persistent
double latitude;
#Persistent
double longitude;
#Persistent
double calorie = 0;
public GeoPtr()
{ //needed for Serializable
}
}
As far as I can see, every class is PersistenceCapable and all the fields are either PersistenceCapable themselves or a collection of it and according to the documentation above it should work.
Ideas?
Thanks
You try to use embedded class Track to store collection of GeoPtr to UserTracks. How DataStore will handle it? When embedding into UserTracks fields of GeoPtr added to common single record in DataStore. You will have:
avgSpeed, distance, ...., speed, time
What DataStore should do in collection case?
avgSpeed, distance, ...., speed_1, time_1, ..., speed_2, time_2, ... speed_N, time_N
???
Is this make any sence?
Don't use embedded. Create three separate classes with primary keys. Use one-to-one relationship for User - UserTracks and one-to-many for UserTracks - GeoPtr.
Read about relations here
Well apparently there is some problem with embedding a collection of user defined classes.
I've read somewhere that its not possible to embed a collection field that has an embedded collection field itself. However, you can achieve almost the same by serializing these fields (you wont be able to index them - that's the difference between serialized to embedded, but I don't need indexes on these fields for my use so it worked out just fine) you can do so by using the next notation :
#Persistent(serialized = "true")
Hoped it will save all of you the pain I've been through.
Bar.

Categories