Unmarshalling XML Fragments at multiple levels of a hierarchy with JAXB - jaxb

I need to un-marshal multiple objects out of an XML Structure that looks like this:
<Control>
<TotalCompanies>2</TotalCompanies>
<TotalSales>100</TotalSales>
<Company>
<Name>ACME Ca</Name>
<TotalSales>70</TotalSales>
<TotalSalesPeople>2</TotalSalesPeople>
<SalesPeople>
<SalesPerson>
<Name>John</Name>
<Sales>40</Sales>
</SalesPerson>
<SalesPerson>
<Name>Joe</Name>
<Sales>30</Sales>
</SalesPerson>
</SalesPeople>
</Company>
<Company>
<Name>ACME Va</Name>
<TotalSales>30</TotalSales>
<TotalSalesPeople>1</TotalSalesPeople>
<SalesPeople>
<SalesPerson>
<Name>Janet</Name>
<Sales>30</Sales>
</SalesPerson>
</SalesPeople>
</Company>
</Control>
I need to be able to separately unmarshall a Control object that contains just the totals and not it's children, and similarly I need to do the same thing at the other levels of the hierarchy. So ideally, my beans would look something like this:
class Control {
int totalCompanies;
int totalSales;
}
class Company {
String name;
int totalSales;
int totalSalesPeople;
}
class SalesPerson {
String name;
int sales;
}
I'm doing this in the context of Spring Batch, but I am pretty sure that doesn't matter. If I restructure the XML some, then I can get it to work (I am pretty sure I won't be allowed to restructure the XML, though). That is, if the objects aren't nested, then it is fine. Similarly, I can get all the SalesPeople out pretty easily.
I can also get the entire tree as an object, and that might work in some cases. However, the real incoming file could be larger than the available memory, so that won't work in practice.
Is there any way to get JAXB, or some other out-of-the-box unmarshaller to do this or do I just need to roll my own based on SAX or STAX?
EDIT:
The system is using Spring Batch to read in large incoming files. The files are not as described above (domain is different), but the structure is the same. The architectural direction is to attempt to use out-of-the-box readers (StaxEventItemReader, e.g.) and unmarshallers (Jaxb2Marshaller, e.g.).
The system will operate in environments where we cannot absolutely guarantee there is sufficient memory to hold the entire file in memory.
I have approaches (custom Stax reader/pre-processing the file/requesting an XSD change) that work, but I wanted to make sure I wasn't missing a feature in the standard reader / unmarshaller implementations that could make this work easily out of the box.

Related

How can I programmatically add a producer method to a CDI container during AfterBeanDiscovery?

I know how to add a Bean to a CDI container during AfterBeanDiscovery. My problem is that what I really need to do is the equivalent of adding a new producer method with the equivalent of a particularly qualified parameter.
That is, I'd like to somehow programmatically create several of these:
#Produces
#SomeQualifier("x")
private Foo makeFoo(#SomeQualifier("x") final FooMaker fm) {
return fm.makeFoo();
}
...where the domain over which SomeQualifier's value element ranges is known only at AfterBeanDiscovery time. In other words, some other portable extension has installed two FooMaker instances into the container: FooMaker-qualified-by-#SomeQualifier("x") and FooMaker-qualified-by-#SomeQualifier("y"). Now I need to do the equivalent of making two producer methods to "match" them.
Nonbinding is not an option; I want this resolution to take place at container startup, not at injection time.
I am aware of BeanManager's getProducerFactory method, but the dozens if not hundreds of lines of gymnastics I'd have to go through to add the right qualifier annotation on each AnnotatedParameter "reachable" from the AnnotatedMethod I'd have to create by hand (to avoid generics issues) make me think I'm way off the beaten path here.
Update: So in my extension, I have created a private static method that returns a Foo, and has a FooMaker parameter. I've wrapped this in a hand-tooled AnnotatedMethod that reports SomeQualifier("x") etc. in its getAnnotations() method, and also reports SomeQualifier("x") etc. from its AnnotatedParameter's getAnnotations() method. Then I got a ProducerFactory from the BeanManager and feed that into a new Bean that I create, where I use it to implement the create and destroy methods. Everything compiles and so forth just fine.
(However, Weld (in particular) blows up with this usage, which leads me to think that I'm doing Really Bad Thingsā„¢.)

How can I get ViewScope value stored as an object in Java?

I have an object stored in the ViewScope: ObjectName (valueA:one, valueB:two)
I stored the values using Java:
ObjectObject location = new ObjectObject();
location.put("valueA", FBSUtility.wrap("one"));
location.put("valueB", FBSUtility.wrap("two"));
Utils.setViewScope("ObjectName", location);
How would I go about retrieving these values from the ViewScope? I've tried doing something like the following:
ObjectObject location;
location = (ObjectObject) ExtLibUtil.getViewScope().get("ObjectName");
but I'm not sure what methods to use to get the values or if this is even the correct path. Thanks in advance for any help.
It's a bit unusual to go out of your way to use the FBS classes, but that path is reasonable enough to accomplish what you want. As long as the latter code is executed after the format, that should retrieve the same object and properly cast it to ObjectObject. After that, you could use location.get("valueA"), etc. to get the values by name, and then whatever methods of FBSValue are appropriate (I'd guess stringValue()).
Incidentally, unless you have a specific need to use these internal classes (like if you're doing something fancy with SSJS functions), it may make sense to use just a normal HashMap<String, Object> instead. SSJS and EL can work with those quite well.

MPS way of attaching additional attributes to concept's properties/references

I've a set of concepts that represent types of entities
Hrrr.
Sample concepts:
Loop with children loopCount: IntegerProperty[1]
HttpRequest with children url: StringProperty[1], hostName: StringProperty[1]
Both concepts extend AbstractTestElement concept (it defines common properties like name, comment, etc).
I want Loop and HttpRequest to be generated to baseLanguage as follows:
Loop:
Loop e = new Loop();
e.setProperty(new IntegerProperty("loopCount", node.loopCount));
HttpRequest:
HttpRequest e = new HttpRequest();
e.setProperty(new StringProperty("url", node.url));
e.setProperty(new IntegerProperty("host", node.hostName));
What I want is to have some common generator template that covers this common logic for setProperty so it is not repeated for different kinds of test elements.
Well, there are properties that require specific-to-test-element treatment, however there are often cases when properties are one-to-one translated, thus
Here's the question: how can I attach metadata to the Loop/HttpRequest concept configuration?
What is MPS-idiomatic way of doing that?
1) While I could use "names of properties" as names put into the new XXXProperty, however ideally I would use HttpRequest.HOST_PROPERTY_NAME kind of references, thus "names of properties" is not sufficient.
2) I might probably invent annotations and annotate properties of my concepts, it looks like MPS itself does not use that approach.
3) (ab)using concept's behaviors to return <quotation new StringProperty("url", node.url) > looks even more awkward.
I would rather not use 2. and 3. because both approaches add generator behavior into aspects of your languages which aren't aware of the fact how things will be generated. It basically tight couples you structure with your generator.
If you go for 1, you can still use that static class approach. By creating a new rootnode in the generator which is a java class and contains all your fields. And then have generic generator template that reduces the IntegerProperty and so on ... If they have a common super concept it should be fairly easy to do. You just have to make sure that the property is generated before the containing concept. That way you can still access the role of it in the parent and use that information to generate the field access.

Can one change/influence JAXB's code generation?

I was wondering whether one can influence the "style" of the code that JAXB generates from XML schema (.xsd) fles. E.g. I would like to:
emit a comment inside newly generated classes, specifically if the class is empty, since that triggers warnings in my environment.
change all setter-methods to return the object instead of "void", so one can do call-chaining like:
X someMethod() {
return new X().setFoo(5).setBar("something");
}
instead of the tedious:
X someMethod() {
X x = new (X);
x.setFoo(5);
x.setBar("something");
return x;
}
Is there some "template" anywhere that JAXB uses and that one could tweak, to achieve such things? Or is that all hard-coded?
M.
There is no template for modifying the generated code easily.
There is, however, a number of plugins. For instance: https://java.net/projects/jaxb2-commons/pages/Fluent-api which is just what you want according to your 2nd bullet.
There are other plugins, e.g. for annotations suppressing warnings - that may help against the 1st bullet.
As an extra, I'd like to mention that not generating Java classes from an XML schema but writing them by hand (plus annotations, of course) is a plausible alternative, provided the XML schema isn't too complex. It may have other advantages besides solving #1 and #2.

Partial objects with JAXB?

I'm working to create some services with JAX-RS, and am relatively new to JAXB (actually XML in general) so please don't assume I know the pre-requisites that I probably should know! Here's the questions: I want to send and receive "partial" objects in XML. That is, imagine one has an object (Java form, obviously) with:
class Thing { int x, String y, Customer z }
I want to be able to send an XML output that contains (dynamically chosen, so I can't use XmlTransient) just x, or just z, or x and y, but not z, or any other combination that suits my client. The point, obviously, is that sometimes the client doesn't need everything, so I can save some bandwidth (particularly with lists of deep, complex objects, which this example clearly doesn't illustrate!).
Also, for input, the same bandwidth argument applies; I would like to be able to have the client send just the particular fields that should be updated in, say, a PUT operation, and ignore the rest, then have the server "merge" those new values onto existing objects and leave the un-mentioned fields unchanged.
This seems to be supported in the Jackson JSON libraries (though I'm still working on it), but I'm having trouble finding it in JAXB. Any ideas?
One thought that I was pondering is whether one can do this in some way via Maps. If I created a Map (potentially nested Maps, for nested coplex objects) of what I want to send, could JAXB send that with a plausible structure? And if it could create such a map on input, I guess I could work through it to make the updates. Not perfect, but maybe?
And yes, I know that the "documents" that will be flying around will probably fail to comply with schemas, having missing fields and all that, but I'm ok with that, provided the infrastructure can be made to work.
Oh, and I know I could do this "manually" with SAX, StAX, or DOM parsing, but I'm hoping there's a rather more automatic way, particularly since JAXB handles the whole objects so effortlessly.
Cheers,
Toby
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
EclipseLink JAXB (MOXy) offerst this support through its object graph extension. Object graphs allow you to specify a subset of properties for the purposes of marshalling an unmarshalling. They may be created at runtime programatically:
// Create the Object Graph
ObjectGraph contactInfo = JAXBHelper.getJAXBContext(jc).createObjectGraph(Customer.class);
contactInfo.addAttributeNodes("name");
Subgraph location = contactInfo.addSubgraph("billingAddress");
location.addAttributeNodes("city", "province");
Subgraph simple = contactInfo.addSubgraph("phoneNumbers");
simple.addAttributeNodes("value");
// Output XML - Based on Object Graph
marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, contactInfo);
marshaller.marshal(customer, System.out);
or statically on the class through annotations:
#XmlNamedObjectGraph(
name="contact info",
attributeNodes={
#XmlNamedAttributeNode("name"),
#XmlNamedAttributeNode(value="billingAddress", subgraph="location"),
#XmlNamedAttributeNode(value="phoneNumbers", subgraph="simple")
},
subgraphs={
#XmlNamedSubgraph(
name="location",
attributeNodes = {
#XmlNamedAttributeNode("city"),
#XmlNamedAttributeNode("province")
}
)
}
)
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
For More Information
http://blog.bdoughan.com/2013/03/moxys-object-graphs-partial-models-on.html
http://blog.bdoughan.com/2013/03/moxys-object-graphs-inputoutput-partial.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

Resources