My goal is to convert the XML to JavaObject and have the JavaObject be able to handle one or more "Tasks".
I would also like to be able to convert the JavaObject to JSON as well.
How can this be done? At it's current state, I am able to convert if only one task exists, anymore results in an error.
I have an XML file that follows this structure:
<Plan>
<ID></ID>
<Comment></Comment>
<CreateTime></CreateTime>
<Task>...</Task>
<Task>...</Task>
<Task>...</Task>
</Plan>
Each Task element is structured like so:
<Task>
<Type></Type>
<Time></Time>
<Target>
<Code></Code>
<TargetId></TargetId>
<Content>
<Stuff1></Stuff1>
<Stuff2></Stuff2>
<Stuff3></Stuff3>
</Content>
</Target>
</Task>
I am able to deserialize the XML when there is only one Task involved. Anymore gives me errors.
My Classes (simplified) are as follows:
#Root(name = "Plan")
public class Plan{
#Element(name = "ID")
private String id;
#Element(name = "Comment")
private String comment;
#Element(name = "CreateTime")
private String createTime;
#Element(name = "Task")
private Task task;
}
#Root(name = "Task")
public class Task{
#Element(name = "Type")
private String type;
#Element(name = "Time")
private String time;
#Element(name = "Target")
private Target target;
}
#Root(name = "Target")
public class Target{
#Element(name = "Code")
private String code;
#Element(name = "TargetId")
private String targetId;
#Element(name = "Content")
private Content content;
}
#Root(name = "Content")
public class Content{
#Element(name = "Stuff1")
private String stuff1;
#Element(name = "Stuff2")
private String stuff2;
#Element(name = "Stuff3")
private String stuff3;
}
In the schema file, I set this but doesn't seem to work:
<xs:element name="Task" type="Task" minOccurs="1" maxOccurs="unbounded">
At it's current state, I am able to convert if only one task exists,
anymore results in an error.
This happens because your element annotation interprets the task tag as a property, so if there is more than one it raises an error. To avoid this behaviour you can use the JacksonXmlElementWrapper annotation you can apply to your task list:
public class Plan {
#JacksonXmlProperty(localName = "Task")
#JacksonXmlElementWrapper(useWrapping = false)
List<Task> tasks;
}
public class Task {}
This above is a starting basic example you can use to define more complicated xmls.
Related
I need to aggregate some data using java and Mongodb.
So my JS script it's that:
db.post.aggregate([
{$match: {date: {$gte: ISODate("2019-08-28T17:50:09.803Z"), $lte: ISODate("2019-12-03T21:45:51.412+00:00")}}},
{$project: {author: 1, _id: 0}},
{$group: {_id: "$author", count: {$sum:1}}}])
And my Java Code using spring+java is:
Aggregation aggregation =
newAggregation(
match(Criteria.where("date")
.lte(dynamicQuery.getEndDate())
.gte(dynamicQuery.getInitDate())),
project("author").andExclude("_id"),
group("author")
.count()
.as("total"));
AggregationResults<Post> result = mongoTemplate.aggregate(aggregation,Post.class, PostSummary.class);
List<Post> map = result.getMappedResults();
And I need to aggregate the sum of documents by authorId. My code returns the user code and no sum of documents.
And we have 2 Collections:
#EqualsAndHashCode(of = "id")
//TODO: Change the #Data to the properly scenario, we don't need
setters in this class anymore.
#Data
#Document (collection = "user")
//TODO: Change collection name to post, because collection are a group
of elements
public class User {
#Id
private String id;
private String name;
private String username;
#Email
private String email;
private String imageUrl;
private String providerId;
private LocalDateTime firstAccess;
}
Post Document:
#Data
#Document(collection = "post")
//TODO: Change collection name to post, because collection are a group of elements
public class Post {
public static final String AUTHOR_FIELD_NAME = "author";
public static final String DATE_FIELD_NAME = "date";
#Id
private String id;
private String content;
#DBRef(lazy = true)
#Field(AUTHOR_FIELD_NAME)
private User author;
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
#Field(DATE_FIELD_NAME)
private LocalDateTime date;
public Post(String content, User author, LocalDateTime date) {
this.content = content;
this.author = author;
this.date = date;
}
}
I have one solution, but I do not know if it is a better solution, so, let's go.
Because the Entity represented inside the Post Domain is one DBRef, the MongoDB does not parse the entire Stringo to the PostSummary.Class
#Getter
#Setter
public class PostSummary {
private User author;
private int count;
}
So, for the solution, I only parse the #Id in the author, and it's working. So If anyone has a better solution we have one solution now.
And should be like this:
#Getter
#Setter
public class PostSummary {
#Id
private User author;
private int count;
}
I am getting two wrapper elements in the XML output generated by Jackson.
I would like to have only one.
I have a Java bean
#Entity
#Table(name = "CITIES")
#JacksonXmlRootElement(localName = "City")
public class City implements Serializable {
private static final long serialVersionUID = 21L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JacksonXmlProperty(isAttribute = true)
private Long id;
#JacksonXmlProperty
private String name;
#JacksonXmlProperty
private int population;
// getters, setters etc
}
and a List wrapper class.
#JacksonXmlRootElement
public class Cities implements Serializable {
private static final long serialVersionUID = 22L;
#JacksonXmlProperty(localName = "City")
#JacksonXmlElementWrapper(localName = "MyCities")
private List<City> cities = new ArrayList<>();
public List<City> getCities() {
return cities;
}
public void setCities(List<City> cities) {
this.cities = cities;
}
}
I am getting this output, which has two wrapper elements. I would like
to remove one of them.
<Cities>
<MyCities>
<City id="1">
<name>Bratislava</name>
<population>432000</population>
</City>
<City id="2">
<name>Budapest</name>
<population>1759000</population>
</City>
<City id="3">
<name>Prague</name>
<population>1280000</population>
</City>
<MyCities>
</Cities>
One of them comes from the ArrayList, one from the class. How to get rid of one of the wrapper elements?
What I want to have is this:
<Cities>
<City id="1">
<name>Bratislava</name>
<population>432000</population>
</City>
<City id="2">
<name>Budapest</name>
<population>1759000</population>
</City>
<City id="3">
<name>Prague</name>
<population>1280000</population>
</City>
</Cities>
"Cities" is the root element, not a wrapper. Wouldn't removing the actual wrapper element "MyCities" work?
Adding #JacksonXmlElementWrapper(useWrapping = false) could also help.
Replacing #JacksonXmlElementWrapper(localName = "MyCities") with #JacksonXmlElementWrapper(useWrapping = false) in Cities should remove the additional wrapper element.
From the documentation:
#JacksonXmlElementWrapper
Allows specifying XML element to use for
wrapping List and Map properties; or disabling use (with 'useWrapping'
set to false).
The fix implemented in Cities:
#JacksonXmlRootElement
public class Cities implements Serializable {
private static final long serialVersionUID = 22L;
#JacksonXmlProperty(localName = "City")
#JacksonXmlElementWrapper(useWrapping = false)
private List<City> cities = new ArrayList<>();
public List<City> getCities() {
return cities;
}
public void setCities(List<City> cities) {
this.cities = cities;
}
}
You could also disable the wrapping functionality directly in the mapper with mapper.setDefaultUseWrapper(false);.
In this case you should simply remove #JacksonXmlElementWrapper(localName = "MyCities") from cities.
I'm trying to fetch just a part of the model using Ebean in Play! Framework, but I'm having some problems and I didn't found any solutions.
I have these models:
User:
#Entity
#Table(name = "users")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class User extends Model{
#Id
private int id;
#NotNull
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name")
private String lastName;
#NotNull
#Column(nullable = false)
private String username;
#NotNull
#Column(nullable = false)
private String email;
private String gender;
private String locale;
private Date birthday;
private String bio;
#NotNull
#Column(nullable = false)
private boolean active;
private String avatar;
#Column(name = "created_at",nullable = false)
private Date createdAt;
#OneToMany
private List<UserToken> userTokens;
// Getters and Setters omitted for brevity
}
UserToken:
#Entity
#Table(name = "user_tokens")
public class UserToken extends Model {
#Id
private int id;
#Column(name = "user_id")
private int userId;
private String token;
#Column(name = "created_at")
#CreatedTimestamp
private Date createdAt;
#ManyToOne
private User user;
// Getters and Setters omitted for brevity
}
And then, I have a controller UserController:
public class UserController extends Controller{
public static Result list(){
User user = Ebean.find(User.class).select("firstName").where().idEq(1).findUnique();
return Results.ok(Json.toJson(user));
}
}
I expected that, when using the .select(), it would filter the fields and load a partial object, but it loads it entirely.
In the logs, there is more problems that I don't know why its happening.
It is making 3 queries. First is the one that I want. And then it makes one to fetch the whole Model, and another one to find the UserTokens. I don't know why it is doing these last two queries and I wanted just the first one to be executed.
Solution Edit
After already accepted the fact that I would have to build the Json as suggested by #biesior , I found (out of nowhere) the solution!
public static Result list() throws JsonProcessingException {
User user = Ebean.find(User.class).select("firstName").where().idEq(1).findUnique();
JsonContext jc = Ebean.createJsonContext();
return Results.ok(jc.toJsonString(user));
}
I render only the wanted fields selected in .select() after using JsonContext.
That's simple, when you using select("...") it always gets just id field (cannot be avoided - it's required for mapping) + desired fields, but if later you are trying to access the field that wasn't available in first select("...") - Ebean repeats the query and maps whole object.
In other words, you are accessing somewhere the field that wasn't available in first query, analyze your controller and/or templates, find all fields and add it to your select (even if i.e. they're commented with common HTML comment in the view!)
In the last version of Play Framework (2.6) the proper way to do this is:
public Result list() {
JsonContext json = ebeanServer.json();
List<MyClass> orders= ebeanServer.find(MyClass.class).select("id,property1,property2").findList();
return ok(json.toJson(orders));
}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<batch-execution>
<insert out-identifier="employee" return-object="true" entry-point="DEFAULT">
<fact xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="employee">
<name>Rajashekhar</name>
<age>21</age>
</fact>
</insert>
<fire-all-rules></fire-all-rules>
</batch-execution>
Now I am getting this output as above but I want out put like below
<batch-execution>
<insert out-identifier="employee" return-object="true"
entry-point="DEFAULT">
<com.practise.Employee>
<name>Rajashekhar</name>
<age>21</age>
</com.practise.Employee>
</insert>
<fire-all-rules />
</batch-execution>
My Jaxb classes are
Request.java
#XmlRootElement(name = "batch-execution")
#XmlAccessorType(XmlAccessType.FIELD)
public class Request implements Serializable {
#XmlElement(name = "insert")
private List<Insert> insert;
#XmlElement(name = "fire-all-rules",nillable=true)
private String fireAllRules = "";
.
..
setters and getter
Insert.java
#XmlAccessorType(XmlAccessType.FIELD)
public class Insert {
#XmlAttribute(name = "out-identifier", required = true)
private String outIdentifier;
#XmlAttribute(name = "return-object")
private boolean returnObject;
#XmlAttribute(name = "entry-point")
private String entryPoint;
private Object fact;
.
.
setters and gettes
com.practise.Employee.java
#XmlRootElement(name="kewill.com.kewill.practoise.Employee")
#XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements java.io.Serializable
{
static final long serialVersionUID = 1L;
#org.kie.api.definition.type.Label("Name")
private java.lang.String name;
#org.kie.api.definition.type.Label("Id")
private java.lang.Integer id;
#org.kie.api.definition.type.Label("Age")
private int age;
#org.kie.api.definition.type.Label(value = "valid")
private java.lang.Boolean valid;
.
. setters and getters
I think it is possible through xtream api but I want to use JAXB please provide me the solution in jaxb.
In Insert.java
added Annotation for
private Object fact;
as
#XmlAnyElement(lax = true)
private Object fact;
Now it is giving expected output.
<?xml version='1.0'?>
<info>
<contract>
<symbol>IBM</symbol>
<sectype>STK</sectype>
<exchange>SMART</exchange>
<currency>USD</currency>
</contract>
<order>
<action>SELL</action>
<quantity>100</quantity>
<ordertype>LMT</ordertype>
<imtprice>imtprice</imtprice>
<transmit>false</transmit>
</order>
</info>
I want to use jaxb annotations with existing java classes to create above XML input but i don't know how create nested xml structure based on Java classes
Try this:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder =
{"contract", "order"}) public class Info
{ #XmlElement(required =
true) private Contract
contract; #XmlElement(required = true) private Order order;
// Getters and setters }
Another class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder = {"symbol",
"sectype", "exchange",
"currency"}) public class
Contract { #XmlElement(required
= true) private String symbol; #XmlElement(required =
true) private String
sectype; #XmlElement(required =
true) private String
exchange; #XmlElement(required
= true) private String currency; //Getters and
setters}
Create an order class the same way.