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.
Related
Using the influxdb library in Java I'm trying to map the results of a query formed using the QueryReactiveAPI query builder to a POJO so I can store them for processing. I get that you need to use the #Measurement annotation on the class definition and the #Column annotation on class variables to map fields but is there the equivalent for tags?
Thanks.
You can also use the #Column annotation for tags, simply include tag = true in the annotation, for example:
#Column(tag = true)
String location;
Source: https://github.com/influxdata/influxdb-client-java#writes-and-queries-in-influxdb-2x
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 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've got the following models in Play Framework.
#Entity
public class Parent extends Model {
#Id
public Long id;
public String name;
public List<Child> children = new ArrayList<Child>();
}
#Entity
public class Child extends Model {
// Entity 2
#Id
public Long id
public String name;
#ManyToOne
public Parent parent;
}
Executing the following query gives me more information than I need.
toJson(Child.find.all());
As an example, I get all children as well as their parents and parent's attributes and any other adjoining information.
I've tried setting the fetch=FetchType.LAZY, but it doesn't make a difference.
Can anyone help?
Jackson's toJson() method always fetches all data while serializing Ebean's objects, so it can be real performance killer, that was discussed my proposition is using some dedicated object (not stored in DB) and filling it only with required data from 'original' object.
Check other answer, which describes this approach.
Ebean has built in JSON support and you can use that if you want exact control over the parts of the object graph to include in JSON:
JsonContext jsonContext = Ebean.json();
JsonWriteOptions options = JsonWriteOptions.parsePath("id,name");
String json = jsonContext.toJson(list2, options);
And alternatively you can apply PathProperties to both the query and json like:
PathProperties pathProperties = PathProperties.parse("id,name");
query.apply(pathProperties);
// fetch only id and name
List<App> list3 = query.findList();
// json output only id and name
JsonWriteOptions options2 = new JsonWriteOptions();
options2.setPathProperties(pathProperties);
String json2 = jsonContext.toJson(list3, options2);
Note that Ebean 4.3 had it's json support refactored to use Jackon core for parsing and generation (so it's using Jackson under the hood). You are using Play so currently stuck on an old version of Ebean so instead of using query.apply() you'd use pathProperties.apply(query) I think.
Regarding #JsonIgnore ... obviously different use cases require different JSON which is why this feature exists in Ebean (when you get a use case that needs to include parent like)
PathProperties pathProperties = PathProperties.parse("id,name,parent(id,name)");
...
I simply opted for the #JsonIgnore annotation.
When using JAXB with Java-First, fields/properties of type java.util.Date are marshalled and unmarshalled as xs:dateTime and everything works as expected.
But if the type of the field/property is Object, JAXB unmarshals xs:dateTimeto XMLGregorianCalendarImpl.
I need to find a way that makes JAXB unmarshal date-time values to java.util.Date by itself using annotations. Otherwise, I'll need to go through all unmarshalled values in each use case.
Even if there were some after-unmarshall-hook to define on the classes containing Object fields and convert the instances manually would be good. But I couldn't find anything that can be used this way either.
Note that I have limited access to the JAXB context, as it is used inside Apache CXF.
In addition to Blaise Doughan's answer:
I could finally figure this out, thanks for help from Blaise Doughan. Actually his answer works with just a small change: if there's several types expected to be unmarshalled as the Object property, there needs to be multiple #XmlElement annotations placed on it using #XmlElements annotation.
Here's my code now:
#XmlElements
({
#XmlElement(name = "dateValue", type = Date.class),
#XmlElement(name = "stringValue", type = String.class),
#XmlElement(name = "booleanValue", type = Boolean.class),
#XmlElement(name = "listValue", type = ArrayList.class),
#XmlElement(name = "bytesValue", type = Byte[].class)
})
public Object getFieldValue()
{
return fieldValue;
}
Note: specifying "name" is required for this to work, since there should be a way for the marshaller / unmarshaller to identify the type of the content.
There are two minor issues here:
You need to specify a list of all of the types expected (which is logical, given the case of marshalling)
There's no way to specify a single name for this property. In my case, where JAXB is used in CXF web services, code generated from WSDL in .NET names this field as "Item". If there was a way, for example, to wrap the XML elements in another one which has a single name, the generated code could be a little bit nicer.
You can set the type property on #XmlElement.
#XmlElement(type=Date.class)
public Object getGenericDateProperty() {
return date;
}
Edit:
Since you don't know the type you could use an XmlAdapter. If the unmarshalled value is an XMLGregorianCalendar convert it to a Date. For more info on XmlAdapter see:
http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html