11.8. Result Class

11.8.1. JavaBean Result Class
11.8.2. Generic 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.20. 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);
List results = (List) 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.21. 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");
List results = (List) 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.22. 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);
List results = (List) 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.23. Populating a Map

Query query = pm.newQuery (Magazine.class);
query.setResult ("title.toUpperCase (), copiesSold");
query.setResultClass (HashMap.class);
List results = (List) 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);

 

Skip navigation bar   Back to Top