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;
}
Related
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
I'm trying to query the Database with a list of Id's and, in case they don't exist, do some stuff with them.
My plan was to do something like
List<Optional<MyObject>> fingById(Set<String> myIds);
I understand this wont' work out of the box because I suppose that even if all the id's where present nothing guarantees me that they will be ordered, so if some of them are present I will get some random null optionals around which I won't be able to may to the Id that returned it.
Basically what I need to do in the end is to retrieve these objects, update one field or create them with default value if not present.
Which is the best way of doing this in batch?
Thanks :)
You could map the results by their id into Map<String, Optional<MyObject>> and then fill in the blanks with Optional.empty().
List<MyObject> findByIdIn(Set<String> ids);
default Map<String, Optional<MyObject>> mapByIdIn(Set<String> ids) {
Map<String, Optional<MyObject>> found = findByIdIn(ids)
.stream()
.collect(Collectors.toMap(MyObject::getId, Optional::of));
ids.stream()
.filter(id -> !found.containsKey(id))
.forEach(id -> found.put(id, Optional.empty()));
return found;
}
I donĀ“t think that it is a good idea to use a List of Optional values. Instead, I recommend to just use the default methods of the repository and query for all existing entities.
List<MyObject> findAll();
After that, you can iterate through all objects and check for missing ids. To improve performance, i recommend the useage of a Map:
var objectMap = repository.findAll().stream()
.collect(Collectors.toMap(MyObject::getId, Function::Identity);
Then, you can simply check if any of the ids is contained in the map:
myIds.stream().filter(objectMap::contains)
.forEach({
// do some stuff, present id
});
myIds.stream().filter((id) -> !myMap.contains(id))
.forEach({
// do some stuff, not present id
});
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 figure this will be easy for someone who really understands JAXB binding files...
Basic Question
How do you configure JAXB to unmarshal multiple elements into the same class?
Note: I want to avoid adding another dependency to my project (like MOXy). Ideally, this can be accomplished with annotations or a custom bindings file.
Background
I have an XML document that contains lots of variations of the same element--each with the exact same properties. Using my example below, all I care about is "Employees" but the XML specifies "directors, managers and staff." For our purposes, these are all subclasses of the same parent and we only need to work with the parent type (Employee) and our object model doesn't have or need instances of the subclasses.
I want JAXB to bind any instance of director, manager, or staff elements into an Employee object.
Example
input:
<organization>
<director>
<fname>Dan</fname>
<lname>Schman</lname>
</director>
<manager>
<fname>Joe</fname>
<lname>Schmo</lname>
</manager>
<staff>
<fname>Ron</fname>
<lname>Schwan</lname>
</staff>
<staff>
<fname>Jim</fname>
<lname>Schwim</lname>
</staff>
<staff>
<fname>Jon</fname>
<lname>Schwon</lname>
</staff>
</organization>
output:
After unmarshalling this example, I would end up with an Organization object with one property: List<Employees> employees where each employee only has a firstName and lastName.
(Note: each employee would be of type Employee NOT Director/Manager/Staff. Subclass information would be lost when unmarshalling. We also don't care about marshaling back out--we only need to create objects from XML)
Can this be done without extensions like MOXy? Can a custom bindings.xjb file save the day?
This corresponds to a choice structure. You could use an #XmlElements annotation for this use case:
#XmlElements({
#XmlElement(name="director", type=Employee.class),
#XmlElement(name="manager", type=Employee.class)
})
List<Employee> getEmployees() {
return employees;
}
If you are starting from an XML schema the following will help:
http://blog.bdoughan.com/2011/04/xml-schema-to-java-xsd-choice.html
I'm looking for best tool/way to create and load JAVA objects from XML definitions.
I had checked out JAXB, seems pretty nice, but didn't find is there a way to work with Entities which properties are dynamic, or changed from time to time, so want to have something like automatic way of working with entities, without converting Object into predefine Entity object. Does something like that exists?
Workflow would be like this read from XML create class for each Entity with dynamic set of attributes and/or create ORM mapping part for those entities and then all manipulation retrieve/store into db or probably will going to use some NoSQL solution like MongoDB.
Note: I'm the EclipseLink JAXB (MOXy) lead, and a member of the JAXB 2 (JSR-222) expert group.
Check out the following EclipseLink example. It demonstrates how to use dynamic properties with both the JPA and JAXB implementations:
http://wiki.eclipse.org/EclipseLink/Examples/MySports
Option #1 - Static Objects with Dynamic Properties
MOXy has an #XmlVirtualAccessMethods extension which allows you to map entries in a map to XML. This allows you to add properties to a static class. In the example below the Customer class has a "real" name property and may have many "virtual" properties.
package blog.metadatasource.refresh;
import java.util.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlVirtualAccessMethods;
#XmlRootElement
#XmlType(propOrder={"firstName", "lastName", "address"})
#XmlVirtualAccessMethods
public class Customer {
private String name;
private Map<String, Object> extensions = new HashMap<String, Object>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object get(String key) {
return extensions.get(key);
}
public void set(String key, Object value) {
extensions.put(key, value);
}
}
The virtual properties are defined via MOXy's XML metadata. In the example below we will add two properties: middleName and shippingAddress.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="blog.metadatasource.refresh">
<java-types>
<java-type name="Customer">
<java-attributes>
<xml-element
java-attribute="middleName"
name="middle-name"
type="java.lang.String"/>
<xml-element
java-attribute="shippingAddress"
name="shipping-address"
type="blog.metadatasource.multiple.Address"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
For More Information
http://blog.bdoughan.com/2011/06/extensible-models-with-eclipselink-jaxb.html
http://blog.bdoughan.com/2011/06/moxy-extensible-models-multi-tenant.html
http://blog.bdoughan.com/2011/06/moxy-extensible-models-multiple.html
http://blog.bdoughan.com/2011/06/moxy-extensible-models-refresh-example.html
Option #2 - Dynamic Objects
MOXy also offers full dynamic object models:
DynamicJAXBContext jaxbContext = DynamicJAXBContextFactory.createContextFromXSD(xsdInputStream, null, null, null);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
DynamicEntity customer = (DynamicEntity) unmarshaller.unmarshal(inputStream);
DynamicEntity address = jaxbContext.newDynamicEntity("org.example.Address");
address.set(street, "123 A Street");
address.set(city, "Any Town");
customer.set("address", address);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(customer, System.out);
For More Information
http://wiki.eclipse.org/EclipseLink/UserGuide/MOXy
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/Dynamic
So, you're basically trying to make POJO's (plain old Java objects) using XML files? They are just like data classes, right?
I'm a big fan of XStream, which is really easy to use and works great if you don't need validation. I've used Castor when validation against a schema was required. I just used XStream to save an object to an xml file and then I can read it back in from anywhere, even if I change the data values associated with the object (which I think is what you mean by "dynamic set of attributes", right?).