I am binding XML to object using JAXB, is it possible to bind based on conditions such as
Bind href attribute in api:page element where attribute position is equal to next.
Or get all records as standard list and then filter out by using if condition
<api:pagination results-count="93" items-per-page="25">
<api:page position="this" href="https://url1.com" />
<api:page position="next" href="https://url1.com?pid=2" />
</api:pagination>
It is not necessary to make a transformation for such a simple setup.Take advantage of #XmlAnyElement https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/XmlAnyElement.html and just map your collection as a list of Elements.
#XmlElementWrapper(name = "pagination")
#XmlAnyElement
public List<Element> getPages() {
return pages;
}
Where Element is org.w3c.dom.Element
The #XmlElementWrapper is optional, if you want you can map your pagination element. I am not sure you need it though.
Then you extract the position with:
page.getAttribute("position")
and
page.getAttribute("href")
for the url
Related
I am trying to map an object what has List inside List with MapStruct. I can mapping parent list but nested list becoming null and cannot mapping.
The JSON like this;
req={
...
SearchCriteriaList:[
{key:"mykey1",values:["val1","val2"]},
{key:"mykey2",values:["val3","val4"]}
]
...
}
I am mapping parent List with this code;
#Mapping(source="searchCriteriaList", target="searchCriteriaList")
And also I want to mapping ;
#Mapping(source="searchCriteriaList.values", target="searchCriteriaList.values")
Is there a way mapping values with with an annotation and witout customize interface.
I'm using the Hibernate Validator 5.2, which features support for Java 8 type_use annotations. I'd like to be able to validate the content of a List inside a Map -- in other words, I just want it to cascade down and validate the contents of Maps and Lists, no matter how they are nested.
A simple Map example:
Map<String, List<Promotion>> promotionsByGroupName = ...;
What I'd like is to be able to do:
#Valid
Map<String, List<#Valid Promotion>> promotionsByGroupName = ...;
However that doesn't work as the standard #Valid annotation cannot be put on that element. So I created a custom annotation that I'm allowed to place there:
#Valid
Map<String, List<#ValidPart Promotion>> promotionsByGroupName = ...;
However, the validator associated with #ValidPart never gets triggered.
The closest I managed to get was to put the #ValidPart annotation on the List like this:
#Valid
Map<String, #ValidPart List<Promotion>> promotionsByGroupName = ...;
...and then unwrap the List in the associated validator to get validate the elements (which unfortunately involves calling a Validator inside the ConstraintValidator and "rewriting" the resulting ConstraintViolations).
My question is therefore, is there a way to do these kinds of nested validations without traversing the List myself? The constraint violation paths this generates are not quite what I'm looking for, as they look like:
promotionsByGroupName[GroupName].[0].name cannot be null
Instead of (no dot between Map key name and Index):
promotionsByGroupName[GroupName][0].name cannot be null
The [0] part is the index of the List which I added myself using addPropertyName in this code:
for (ConstraintViolation<?> violation : validator.validate(value)) {
NodeBuilderCustomizableContext builder = context
.buildConstraintViolationWithTemplate(violation.getMessage())
.addPropertyNode("[" + i + "]");
for (String nodeName : violation.getPropertyPath().toString().split("\\.")) {
builder = builder.addPropertyNode(nodeName);
}
builder.addConstraintViolation();
}
Not at the moment. This type of nested unwrapping is currently not supported with Hibernate Validator.
As a work-around, you might create a specific collection type Promotions which you use as map values instead of List<Promotion>.
I need to parse an XML element that may have multiple format, depending on user needs. This format is implemented as "any" element in the XSD.
I have found that it is possible to do it with JAXB with #XmlAnyElement annotation :
#XmlAnyElement
protected List<Element> any;
But I would like to know how do it using Simple Xml framework. Is it possible ? Will I need to mix both JAXB and SimpleXml ?
Here is the same question on Simple support : http://ehc.ac/p/simple/mailman/message/33015962/
SimpleXml has the Element*Union feature exactly for this use case. Have a look at the following, which maps a list of interface Result to either the Result1 or Result2 implementation:
#Root(name = "response", strict = false)
public class Response {
#ElementListUnion({
#ElementList(inline = true, type = Result1.class, required=false),
#ElementList(inline = true, type = Result2.class, required=false)
})
private #Nullable List<Result> resultList;
...
SimpleXml tries and binds one or the other implementation, that is why it is advisable to have a common interface for your getters. Of course you still need to write a model which matches with the xml in input in some way, but the union can help to reduce heterogeneous data input to your business/software domain.
I am parsing an XML file like
<STRUCTURE ID="EV_Se96ffb9a-df1f-44e7-a4f8-818688cf8d3b">
<SHORT-NAME>STRUCT</SHORT-NAME>
<LONG-NAME>Structure</LONG-NAME>
</STRUCTURE>
where I am getting the child nodes of STRUCTURE and adding it to a nodeList.
Can I have an option to add the attributes of STRUCTURE i.e, ID to a nodeList ?
How to convert the attributes to a node and add it to a nodelist ?
Please help me out.
I am using the DOM parsing strategy
The Node class has a method getAttributes() which returns a NamedNodeMap. Of course, only elements will return an appropriate named node map (as only elements can have attributes).
On such a NamedNodeMap you can then retrieve the attribute node via a call to getNamedItem(String) or via a call to item(int). Note, that the return type of these methods is a Node, which - in case of attributes - will in fact be an Attr.
How maintain the order of unmarshalled child objects in a Set. Below is my xml, when converting to java objects order that I get in set is not A,B,C. How can I achieve that?
<company id="abc">
<emp name="A"/>
<emp name="B"/>
<emp name="C"/>
</company>
Edit:
Observations:
In my Company.class I had defined Set<Employee> and when xstream unmarshall it, it create the set as HashMap, so the order is not maintained.
Ques) How can I use LinkedHashMap in xstream to maintain the order?
Then I defined the employee set as LinkedHashSet<Employee>. Doing this xstream create set as LinkedHashMap and order is maintained but Hibernate throws exception because there I have defined Set <set name="employees"> and it throws error on casting Set to LinkedHashSet
public void setEmployees(Set<Employee> emps){
this.packages = (LinkedHashSet<Employee>)emps;
}
Set is not ordered. If you like deifnite order, use list. This has nothing with xstream.
I believe you are looking for ordering based on the content and not the order in which the emp element occurs in the XML instance. If this is the case then SortedSet can maintain natural ordering. But not sure how xstream unmarshalls it though. If there is a way to map it to SortedSet then you achieve what you are looking for.
If you want the data ordered by their occurence in XML instance then you could ask xtream to map it to List implementations but I am not sure xstream guarantees this behavior.
If order is important then my suggestion is to make it explicitly part of the contract by adding an order or index attribute to emp element.
I solved the problem using my custom Converter but I guess there has to be a better way that to used custom converter for such a small problem. I'll keep looking but until then.
Add this
xstream.registerConverter(new CompanyConverter());
public Object unmarshal(HierarchicalStreamReader reader,UnmarshallingContext context) {
Company comp = new Company();
Set<Employee> packages = new LinkedHashSet<Employee>();
while(reader.hasMoreChildren()){
reader.moveDown();
if("emp".equals(reader.getNodeName())){
Employee emp = (Employee)context.convertAnother(comp, Employee.class);
employees.add(emp);
}
reader.moveUp();
}
comp.setEmployees(employees);
return comp;
}