Skip to content
GigaSpaces Logo GigaSpaces Logo
  • Products
    • InsightEdge Portfolio
      • Smart Cache
      • Smart ODS
      • Smart Augmented Transactions
    • GigaSpaces Cloud
  • Roles
    • Architects
    • CXOs
    • Product Teams
  • Solutions
    • Industry Solutions
      • Financial Services
      • Insurance
      • Retail and eCommerce
      • Telecommunications
      • Transportations
    • Technical Solutions
      • Operational BI
      • Mainframe & AS/400 Modernization
      • In Memory Data Grid
      • Transactional and Analytical Processing (HTAP)
      • Hybrid Cloud Data Fabric
      • Multi-Tiered Storage
      • Kubernetes Deployment
      • Streaming Analytics for Stateful Apps
  • Customers
  • Company
    • About GigaSpaces
    • Customers
    • Partners
    • Support & Services
      • University
      • Services
      • Support
    • News
    • Contact Us
    • Careers
  • Resources
    • Webinars
    • Blog
    • Demos
    • Solution Briefs & Whitepapers
    • Case Studies
    • Benchmarks
    • ROI Calculators
    • Analyst Reports
    • eBooks
    • Technical Documentation
  • Contact Us
  • Try Free

Fun with XStream

Subscribe to our blog!

Subscribe for Updates
Close
Back

Fun with XStream

Joe Ottinger February 15, 2011
4 minutes read

XStream unmarshalling is great fun when you’re not working with a fixed schema.

I’ve been working on a quick start document for GigaSpaces‘ data grid edition lately, and I’m doing it with the code in the form of tests. This makes writing it really easy (run the tests, make sure it works, if it fails, wash, rinse, repeat), but that’s not what this post is about.

For each test, I clear out the data grid, and then populate it; I then act on the grid in various ways to show operations.

One of the operations I’m testing is a query-by-example facility, where you create an example object (using null for wildcards by default), populating a few fields, then ask the data grid to hand back all matching objects.
However, this means the object hierarchies have to be somewhat similar, shall we say. If you have two branches of objects, it doesn’t work.

So here’s what I have:

  1. a POJO with a few fields (id, first name, last name, a list of addresses).
  2. a document (a type of Map) with accessors and mutators that modify and query the map, so setFirstName(String name) just performs this.setProperty(“firstName”, name);. Exciting, exciting, I know – but the documents are schemaless, so theoretically (and, well, in real life) I can dynamically add properties to the type at will.

Nothing too spectacular here – except these are different object trees (DocumentContact has no relation to NativeContact, although they both implement Contact). When I was loading the data, I loaded the items as NativeContacts, because it was simple.

Before we go too far, this is important: the schemaless types and the static types are compatible in XAP. I’m going to be including that in the quick start, but for this particular test the compatibility is not being enforced. The problem isn’t XAP or  the compatibility; it’s in how I’m doing it at this point in the test.

So what I needed to do was clear: load the contacts as DocumentContacts instead of NativeContacts.
At first, I thought, “Oh, that’s simple: instead of aliasing the ‘contact’ node to NativeContact, alias it to DocumentContact.”

This failed in neat and dramatic ways.
The reason: XStream is really quite good at converting streams of text to objects and back, and it does a very complete conversion… by using direct field access. So it doesn’t use accessors to do getFirstName() or setFirstName() – it goes straight to the firstName attribute itself. (This is how it can modify read-only properties, for example.)

But with the DocumentContact… there are no fields. It’s a map. So XStream barfs, because it can’t find attributes that map to the input.
The solution, as the XStream gurus are now screaming at me, is to use a Converter. A converter allows me to override XStream’s default resolution mechanisms with my own, so I can use method resolution if I want to. So here’s what I ended up with in my converter:

@Override
    public Object unmarshal(HierarchicalStreamReader reader,
                            UnmarshallingContext unmarshallingContext)
            throws Error {
        try {
            DocumentContact c = new DocumentContact();
            do {
                reader.moveDown();
                if (reader.getNodeName().equals("addresses")) {
                    List <Address> addresses =
                            (List<Address>) unmarshallingContext
                               .convertAnother(c, List.class);
                    c.setAddresses(addresses);
                } else {
                    String methodName = "set" +
                            reader.getNodeName().toUpperCase().charAt(0) +
                            reader.getNodeName().substring(1);
                    Method m = aClass.getMethod(methodName, String.class);
                    m.invoke(c, reader.getValue());
                }
                reader.moveUp();
            } while (reader.hasMoreChildren());
            return c;
        } catch (Exception e) {
            throw new Error();
        }
    }

Now, before you decide to rail at me, let’s look at the flaws in this code, because there are many.

  1. Error checking! The actual code I use does things a little better, shall we say. The error checking here is simplified or eliminated altogether because it’s ginormous.
  2. Performance. No caching, no memoization. In real production code, I’d be saving off all those calculated fields (methodName, m), and might even memoize a storage mechanism (strategy pattern for different field types, for example, since here we have an embedded collection). However: test code. Simple objects with either String attributes or a List of addresses. Considering the scope of the problem, a direct (and slow) solution is satisfactory.

But this code is indeed able to now repopulate my schemaless contacts (from a document created from contacts with a schema.)
It’s not earth-shattering, but I figured someone else might have similar issues with XStream in a similar schemaless environment (consider JCR or, of course, our Data Grid) and this might be helpful to show a solution.

CATEGORIES

  • GigaSpaces
  • Java
  • syndicated
Joe Ottinger

All Posts (12)

YOU MAY ALSO LIKE

December 16, 2007

TechTalk with Nati Shalom is…
1 minutes read

March 19, 2015

Making IMC More Cost Effective…
4 minutes read

September 5, 2008

GigaSpaces’ upcoming cloud framework
3 minutes read
  • Copied to clipboard

PRODUCTS, SOLUTIONS & ROLES

  • Products
  • InsightEdge Portfolio
    • Smart Cache
    • Smart ODS
    • Smart Augmented Transactions
    • Compare InsightEdge Products
  • GigaSpaces Cloud
  • Roles
  • Architects
  • CXOs
  • Product Teams
  • Solutions
  • Industry
    • Financial Services
    • Insurance
    • Retail and eCommerce
    • Telecommunications
    • Transportation
  • Technical
    • Operational BI
    • Mainframe & AS/400 Modernization
    • In Memory Data Grid
    • HTAP
    • Hybrid Cloud Data Fabric
    • Multi-Tiered Storage
    • Kubernetes Deployment
    • Streaming Analytics for Stateful Apps

RESOURCES

  • Resource Hub
  • Webinars
  • Blogs
  • Demos
  • Solution Briefs & Whitepapers
  • Case Studies
  • Benchmarks
  • ROI Calculators
  • Analyst Reports
  • eBooks
  • Technical Documentation
  • Featured Case Studies
  • Mainframe Offload with Groupe PSA
  • Digital Transformation with Avanza Bank
  • High Peak Handling with PriceRunner
  • Optimizing Business Communications with Avaya

COMPANY

  • About
  • Customers
  • Management
  • Board Members
  • Investors
  • News
  • Events
  • Careers
  • Contact Us
  • Book A Demo
  • Try GigaSpaces For Free
  • Partners
  • OEM Partners
  • System Integrators
  • Value Added Resellers
  • Technology Partners
  • Support & Services
  • University
  • Services
  • Support
Copyright © GigaSpaces 2021 All rights reserved | Privacy Policy
LinkedInTwitterFacebookYouTube

Contact Us