11.8. Result Class
Prev | Chapter 11. Query | Next

## 11.8. Result Class

Queries have the ability to pack result data into a custom result class. You might use this feature for anything from populating data transfer objects automatically, to avoiding the casting and other inconveniences involved in dealing with the `Object[]`s normally generated by multi-valued projections. You specify a custom result class with the `setResultClass` method.

    public void setResultClass (Class resultClass);

### 11.8.1. JavaBean Result Class

JDO populates result objects by matching the result class' public fields and JavaBean setter methods to the expressions defined in the query result string. The result class must be public (or otherwise instantiable via reflection), and must have a no-args constructor.

Example 11.19. Populating a JavaBean

    public class SalesData
    {
        private double price;
        private int copiesSold;

        public void setPrice (double price)
        {
            this.price = price;
        }

        public double getPrice ()
        {
            return price;
        }

        public void setCopiesSold (int copiesSold)
        {
            this.copiesSold = copiesSold;
        }

        public int getCopiesSold ()
        {
            return copiesSold;
        }
    }

    Query query = pm.newQuery (Magazine.class);
    query.setResult ("price, copiesSold");
    query.setResultClass (SalesData.class);
    Collection results = (Collection) query.execute ();
    for (Iterator itr = results.iterator (); itr.hasNext ();)
        processSalesData ((SalesData) itr.next ());
    query.close (results);

The example above is simple enough; the names of the projected fields are matched to the setter methods in the result class. But what if the names don't match? What if the result expressions contain aggregates, mathematical expressions, and relation traversals, all of which contain symbols that can't match a field or setter method name?

JDO provides the answer in the form of result expression aliases. An alias is a label assigned to a particular result expression for the purposes of matching that expression to fields or methods in the result class. To demonstrate this, let's modify our example above to populate each `SalesData` object not with the price and copies sold of each magazine, but with the average price and total copies sold of all magazines published by each company.

Example 11.20. Result Aliases

    Query query = pm.newQuery (Magazine.class);
    query.setResult ("avg(price) as price, sum(copiesSold) as copiesSold");
    query.setResultClass (SalesData.class);
    query.setGrouping ("publisher");
    Collection results = (Collection) query.execute ();
    for (Iterator itr = results.iterator (); itr.hasNext ();)
        processSalesData ((SalesData) itr.next ());
    query.close (results);

Earlier in this chapter, we mentioned that the default result string for a query is `distinct this as C`, where `C` is the unqualified name of the candidate class. Now, finally, the meaning of this default string should be clear. But just to make it concrete, here is an example:

Example 11.21. Taking Advantage of the Default Result String

    public class Wrapper
    {
        private Magazine mag;

        public void setMagazine (Magazine mag)
        {
            this.mag = mag;
        }

        public Magazine getMagazine ()
        {
            return mag;
        }
    }

    Query query = pm.newQuery (Magazine.class);
    query.setResultClass (Wrapper.class);
    Collection results = (Collection) query.execute ();
    for (Iterator itr = results.iterator (); itr.hasNext ();)
        processWrapper ((Wrapper) itr.next ());
    query.close (results);

In this query on the `org.mag.Magazine` class, the default result string is `distinct this as Magazine`. Because our result class has a corresponding `setMagazine` method, the query can automatically populate each `Wrapper` with a matching magazine.

### 11.8.2. Generic Result Class

Whenever the specified result class does not contain a public field or setter method matching a particular result expression, the query looks for a method named `put` that takes two `Object` arguments. If found, the query invokes that method with the result expression or alias as the first argument, and its value as the second argument. This not only means that you can include a generic `put` method in your custom result classes, but that any `Map` implementation is suitable for use as a query result class.

Example 11.22. Populating a Map

    Query query = pm.newQuery (Magazine.class);
    query.setResult ("title.toUpperCase (), copiesSold");
    query.setResultClass (HashMap.class);
    Collection results = (Collection) query.execute ();
    for (Iterator itr = results.iterator (); itr.hasNext ();)
    {
        HashMap map = (HashMap) itr.next ();
        processData (map.get ("title.toUpperCase ()"), map.get ("copiesSold"));
    }
    query.close (results);

Prev | Up | Next
11.7. Aggregates | Home | 11.9. Single-String JDOQL