All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.datanucleus.query.evaluator.AbstractResultClassMapper Maven / Gradle / Ivy

Go to download

DataNucleus Core provides the primary components of a heterogenous Java persistence solution. It supports persistence API's being layered on top of the core functionality.

There is a newer version: 6.0.7
Show newest version
/**********************************************************************
Copyright (c) 2007 Marcel Wirth and others. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Contributors:
2008 Andy Jefferson - reworked to make extensive reuse of QueryUtils
    ...
 **********************************************************************/
package org.datanucleus.query.evaluator;

import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.query.QueryUtils;
import org.datanucleus.query.expression.Expression;
import org.datanucleus.query.expression.ParameterExpression;
import org.datanucleus.query.expression.PrimaryExpression;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;
import org.datanucleus.util.StringUtils;

/**
 * Abstract mapper for getting results from a query. Extend for the specific query language.
 */
public class AbstractResultClassMapper
{
    protected Class resultClass;

    public AbstractResultClassMapper(Class resultClass)
    {
        this.resultClass = resultClass;
    }

    /**
     * Method to map the input results to the required result class type.
     * @param inputResults The results to process
     * @param resultNames Expressions for the result components of the input results (columns)
     * @return Collection<resultClass>
     */
    public Collection map(final Collection inputResults, final Expression[] resultNames)
    {
        // Do as PrivilegedAction since can use reflection
        return (Collection) AccessController.doPrivileged(new PrivilegedAction()
        {
            public Object run()
            {
                String[] fieldNames = new String[resultNames.length];
                Field[] fields = new Field[fieldNames.length];
                for (int i=0;i 0)
                        {
                            // Just take last part of name (for when the user specifies something like "p.firstName")
                            int pos = fieldNames[i].lastIndexOf('.');
                            fieldNames[i] = fieldNames[i].substring(pos+1);
                        }
                        fields[i] = getFieldForFieldNameInResultClass(resultClass, fieldNames[i]);
                    }
                    else if (resultNames[i] instanceof ParameterExpression)
                    {
                        // TODO We need to cater for outputting the parameter value. Need SymbolTable
                        // This code below is wrong.
                        fieldNames[i] = ((ParameterExpression)resultNames[i]).getId();
                        fields[i] = getFieldForFieldNameInResultClass(resultClass, fieldNames[i]);
                    }
                    else
                    {
                        fieldNames[i] = resultNames[i].getAlias();
                        fields[i] = null;
                    }
                }
    
                List outputResults = new ArrayList();
                Iterator it = inputResults.iterator();
                while (it.hasNext())
                {
                    Object inputResult = it.next();
                    Object row = getResultForResultSetRow(inputResult, fieldNames, fields);
                    outputResults.add(row);
                }
                return outputResults;
            }
        });
    }

    /**
     * Method to take the result(s) of a row of the query and convert it into an object of the resultClass
     * type, using the rules from the JDO spec.
     * @param inputResult The result from the query
     * @param fieldNames Names of the fields (in the query, ordered)
     * @param fields The Field objects for the fields of the result class (ordered)
     * @return Object of the resultClass type for the input result
     */
    Object getResultForResultSetRow(Object inputResult, String[] fieldNames, Field[] fields)
    {
        if (resultClass == Object[].class)
        {
            return inputResult;
        }
        else if (QueryUtils.resultClassIsSimple(resultClass.getName()))
        {
            // User wants a single field
            if (fieldNames.length == 1)
            {
                if (inputResult == null || resultClass.isAssignableFrom(inputResult.getClass()))
                {
                    return inputResult;
                }

                String msg = Localiser.msg("021202", resultClass.getName(), inputResult.getClass().getName());
                NucleusLogger.QUERY.error(msg);
                throw new NucleusUserException(msg);
            }
            else if (fieldNames.length > 1)
            {
                String msg = Localiser.msg("021201", resultClass.getName());
                NucleusLogger.QUERY.error(msg);
                throw new NucleusUserException(msg);
            }
            else
            {
                // 0 columns in the query ?
                return null;
            }
        }
        else if (fieldNames.length == 1 && resultClass.isAssignableFrom(inputResult.getClass()))
        {
            // Only 1 column, and the input result is of the type of the result class, so return it
            return inputResult;
        }
        else
        {
            Object[] fieldValues = null;
            if (inputResult instanceof Object[])
            {
                fieldValues = (Object[])inputResult;
            }
            else
            {
                fieldValues = new Object[1];
                fieldValues[0] = inputResult;
            }
            Object obj = QueryUtils.createResultObjectUsingArgumentedConstructor(resultClass, fieldValues, null);
            if (obj != null)
            {
                return obj;
            }
            else if (NucleusLogger.QUERY.isDebugEnabled())
            {
                // Give debug message that no constructor was found with the right args
                Class[] ctr_arg_types = new Class[fieldNames.length];
                for (int i=0;i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy