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
Related
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.
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.
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.
I am trying to save an Object which implements an Interface say IInterface.
private PersistentDictionary<string, IInterface> Object = new PersistentDictionary<string, IInterface>(Environment.CurrentDirectory + #"\Object");
Since many classes implement the same interface(all of which need to cached), for a generic approach I want to store an Object of type IInterface in the dictionary.
So that anywhere I can pull out that object type cast it as IInterface and use that object's internal implementation of methods etc..
But, as soon as the Esent cache is initialized it throws this error:
Not supported for SetColumn
Parameter name: TColumn
Actual value was IInterface.
I have tried to not use XmlSerializer to do the same but is unable to deserialize an Interface type.Also, [Serializable] attribute cannot be used on top of a Interface, so I am stuck.
I have also tried to make all the implementations(classes) of the Interface as [Serializable] as a dying attempt but to no use.
Does any one know a way out ? Thanks in advance !!!
The only reason that only structs are supported (as well as some basic immutable classes such as string) is that the PersistentDictionary is meant to be a drop-in replacement for Dictionary, SortedDictionary and other similar classes.
Suppose I have the following code:
class MyClass
{
int val;
}
.
.
.
var dict = new Dictionary<int,MyClass>();
var x = new MyClass();
x.val = 1;
dict.Add(0,x);
x.val = 2;
var y = dict[0];
Console.WriteLine(y.val);
The output in this case would be 2. But if I'd used the PersistentDictionary instead of the regular one, the output would be 1. The class was created with value 1, and then changed after it was added to the dictionary. Since a class is a reference type, when we retrieve the item from the dictionary, we will also have the changed data.
Since the PersistentDictionary writes the data to disk, it cannot really handle reference types this way. Serializing it, and writing it to disk is essentially the same as treating the object as a value type (an entire copy is made).
Because it's intended to be used instead of the standard dictionaries, and the fact that it cannot handle reference types with complete transparency, the developers instead opted to support only structs, because structs are value types already.
However, if you're aware of this limitation and promise to be careful not to fall into this trap, you can allow it to serialize classes quite easily. Just download the source code and compile your own version of the EsentCollections library. The only change you need to make to it is to change this line:
if (!(type.IsValueType && type.IsSerializable))
to this:
if (!type.IsSerializable)
This will allow classes to be written to the PersistentDictionary as well, provided that it's Serializable, and its members are Serializable as well. A huge benefit is that it will also allow you to store arrays in there this way. All you have to keep in mind is that it's not a real dictionary, therefore when you write an object to it, it will store a copy of the object. Therefore, updating any of your object's members after adding them to the PersistentDictionary will not update the copy in the dictionary automatically as well, you'd need to remember to update it manually.
PersistentDictionary can only store value-structs and a very limited subset of classes (string, Uri, IPAddress). Take a look at ColumnConverter.cs, at private static bool IsSerializable(Type type) for the full restrictions. You'd be hitting the typeinfo.IsValueType() restriction.
By the way, you can also try posting questions about PersistentDictionary at http://managedesent.codeplex.com/discussions .
-martin
I'm using db4o with groovy (actually griffon). I'm saving dozen of objects into db4o objectSet and see that .yarv file size is about 11Mb. I've checked its content and found that it stores metaClass with all nested fields into every object. It's a waste of space.
Looking for the way to avoid storing of metaClass and therefore reduce the size of result .yarv file, since I'm going to use db4o to store millions of entities.
Should I try callConstructors(true) db4o configuration? Think it would help?
Any help would be highly appreciated.
As an alternative you can just store 'Groovy'-beans instances. Those are compiled down to regular Java-ish classes with no special Groovy specific code attached to them.
Just like this:
class Customer {
// properties
Integer id
String name
Address address
}
class Address{
String street;
}
def customer = new Customer(id:1, name:"Gromit", address:new Address(street:"Fun"))
I don't know groovy but based on your description every groovy object carries metadata and you want to skip storing these objects.
If that is the case installing a "null translator" (TNull class) will cause the "translated" objects to not be stored.
PS: Call Constructor configuration has no effect on what gets stored in the db; it only affects how objects are instantiated when reading from db.
Hope this helps