org.batoo.jpa.core.impl.nativeQuery.NativeQuery.java Source code

Java tutorial

Introduction

Here is the source code for org.batoo.jpa.core.impl.nativeQuery.NativeQuery.java

Source

/*
 * Copyright (c) 2012 - Batoo Software ve Consultancy Ltd.
 * 
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.batoo.jpa.core.impl.nativeQuery;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Parameter;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import javax.persistence.TemporalType;

import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.lang.NotImplementedException;
import org.batoo.common.log.BLogger;
import org.batoo.common.log.BLoggerFactory;
import org.batoo.jpa.core.impl.instance.EnhancedInstance;
import org.batoo.jpa.core.impl.instance.ManagedId;
import org.batoo.jpa.core.impl.instance.ManagedInstance;
import org.batoo.jpa.core.impl.manager.EntityManagerImpl;
import org.batoo.jpa.core.impl.manager.SessionImpl;
import org.batoo.jpa.core.impl.model.EntityTypeImpl;
import org.batoo.jpa.core.impl.model.mapping.AbstractMapping;
import org.batoo.jpa.core.impl.model.mapping.BasicMappingImpl;
import org.batoo.jpa.core.impl.model.mapping.EmbeddedMappingImpl;
import org.batoo.jpa.core.impl.model.mapping.SingularAssociationMappingImpl;
import org.batoo.jpa.core.impl.model.mapping.SingularMappingEx;
import org.batoo.jpa.jdbc.AbstractColumn;
import org.batoo.jpa.jdbc.BasicColumn;
import org.batoo.jpa.jdbc.dbutils.QueryRunner;
import org.batoo.jpa.parser.metadata.ColumnResultMetadata;
import org.batoo.jpa.parser.metadata.EntityResultMetadata;
import org.batoo.jpa.parser.metadata.FieldResultMetadata;
import org.batoo.jpa.parser.metadata.SqlResultSetMappingMetadata;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * The implementation of the native query interface.
 * 
 * @author hceylan
 * @author asimarslan
 * @since 2.0.0
 */
public class NativeQuery implements Query, ResultSetHandler<List<Object>> {

    /**
     * Model class for fieldResult mapping for high perf iteration on sql resultsets
     * 
     * @author asimarslan
     * @since $version
     */
    private static class IdModel {

        public static final String DEFAULT_EMBEDDED_ID = "__pk__";
        public static final String DEFAULT_ID = "__id__";

        public static IdModel merge(IdModel idModel, String embeddedId, String id, String column) {
            idModel = idModel != null ? idModel : new IdModel();
            idModel.merge(embeddedId, id, column);
            return idModel;
        }

        HashMap<String, Object> idMap = Maps.newHashMap();

        String embeddedId;

        private IdModel() {
            super();
        }

        public String getEmbeddedId() {
            return this.embeddedId;
        }

        public HashMap<String, Object> getIdMap() {
            return this.idMap;
        }

        private void merge(String embeddedId, String id, String column) {
            this.embeddedId = embeddedId;
            this.idMap.put(id, column);
        }

        @Override
        public String toString() {
            if (this.idMap.values().size() == 1) {
                return this.idMap.values().iterator().next().toString();
            }
            return null;
        }

    }

    private static final BLogger LOG = BLoggerFactory.getLogger(NativeQuery.class);

    private final EntityManagerImpl em;
    private final String query;
    private final Class<?> resultClass;

    private FlushModeType flushMode;
    private int maxResults;
    private int firstResult;

    private final HashMap<Integer, NativeParameter<?>> parameters = Maps.newHashMap();
    private final HashMap<NativeParameter<?>, Object> parameterValues = Maps.newHashMap();

    private final Map<String, Object> hints = Maps.newHashMap();

    private List<?> results;

    final SqlResultSetMappingMetadata sqlResultSetMapping;

    // Map of entity-name, map of fied-name, column-name
    private final HashMap<String, HashMap<String, Object>> fieldMap = Maps.newHashMap();

    /**
     * @param entityManager
     *            the entity manager
     * @param query
     *            the native SQL query
     * 
     * @since 2.0.0
     */
    public NativeQuery(EntityManagerImpl entityManager, String sqlString) {
        super();

        this.em = entityManager;
        this.query = sqlString;
        this.resultClass = null;
        this.sqlResultSetMapping = null;
    }

    /**
     * @param entityManager
     *            the entity manager
     * @param sqlString
     *            the native SQL query
     * @param resultClass
     *            the result class
     * 
     * @since 2.0.0
     */
    public NativeQuery(EntityManagerImpl entityManager, String sqlString, Class<?> resultClass) {
        super();

        this.em = entityManager;
        this.query = sqlString;
        this.resultClass = resultClass;
        this.sqlResultSetMapping = null;
    }

    /**
     * 
     * @param entityManagerImpl
     * @param sqlString
     * @param resultSetMapping
     * @since $version
     */
    public NativeQuery(EntityManagerImpl entityManager, String sqlString, String resultSetMapping) {
        super();

        this.em = entityManager;
        this.query = sqlString;
        this.resultClass = null;

        this.sqlResultSetMapping = this.em.getMetamodel().getSqlResultSetMapping(resultSetMapping);
        if (this.sqlResultSetMapping == null) {
            throw new PersistenceException("SqlResultSetMapping does not exist! : " + resultSetMapping);
        } else {
            for (final EntityResultMetadata entityResultMetadata : this.sqlResultSetMapping.getEntities()) {
                final HashMap<String, Object> _fieldModelMap = Maps.newHashMap();

                for (final FieldResultMetadata field : entityResultMetadata.getFields()) {
                    final String[] split;
                    if (field.getName().contains(".")) {
                        split = field.getName().split("\\.");
                    } else {
                        split = new String[] { field.getName(), IdModel.DEFAULT_EMBEDDED_ID, IdModel.DEFAULT_ID };
                    }

                    final String attr = split[0];
                    final String embId = split.length > 2 ? split[split.length - 2] : IdModel.DEFAULT_EMBEDDED_ID;
                    final String id = split.length > 1 ? split[split.length - 1] : IdModel.DEFAULT_ID;

                    _fieldModelMap.put(attr,
                            IdModel.merge((IdModel) _fieldModelMap.get(attr), embId, id, field.getColumn()));

                }
                this.fieldMap.put(entityResultMetadata.getEntityClass(), _fieldModelMap);
            }

        }

    }

    private Object convertTemporal(TemporalType temporalType, Calendar value) {
        switch (temporalType) {
        case DATE:
            return new java.sql.Date(value.getTimeInMillis());
        case TIME:
            return new java.sql.Time(value.getTimeInMillis());
        default:
            return new java.sql.Timestamp(value.getTimeInMillis());
        }
    }

    private Object convertTemporal(TemporalType temporalType, Date value) {
        switch (temporalType) {
        case DATE:
            return new java.sql.Date(value.getTime());
        case TIME:
            return new java.sql.Time(value.getTime());
        default:
            return new java.sql.Timestamp(value.getTime());
        }
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public int executeUpdate() {
        this.em.assertTransaction();

        // flush if specified
        if ((this.flushMode == FlushModeType.AUTO) || (this.em.getFlushMode() == FlushModeType.AUTO)) {
            this.em.flush();
        }

        try {
            if (!this.parameters.isEmpty()) {
                final Object[] parameters = new Object[this.parameters.size()];

                for (int i = 0; i < this.parameters.size(); i++) {
                    parameters[i] = this.getParameterValue(i);
                }

                return new QueryRunner(this.em.getJdbcAdaptor(), false).update(this.query, parameters);
            }

            return new QueryRunner(this.em.getJdbcAdaptor(), false).update(this.query);

        } catch (final SQLException e) {
            throw new PersistenceException("Native query execution has failed!", e);
        }
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public int getFirstResult() {
        return this.firstResult;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public FlushModeType getFlushMode() {
        return this.flushMode;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public Map<String, Object> getHints() {
        return Collections.unmodifiableMap(this.hints);
    }

    /**
     * Transforms the column names for idField Map using a field,column-name map
     * 
     * @return
     * @param idFields
     * @param _fieldMap
     * @since $version
     */
    private HashMap<AbstractColumn, String> getIdFieldTransformed(HashMap<AbstractColumn, String> idFields,
            HashMap<String, Object> fieldIdMap) {
        if (fieldIdMap == null) {
            return idFields;
        }
        final HashMap<AbstractColumn, String> idFieldsMod = Maps.newHashMap();
        final BiMap<String, AbstractColumn> inverse = HashBiMap.create(idFields).inverse();
        for (final String field : idFields.values()) {
            final AbstractColumn column = inverse.get(field);
            final String _field = column.getMapping().getName();

            final Object colmVal = fieldIdMap.get(_field);

            if (colmVal != null && colmVal.toString() != null) {
                idFieldsMod.put(column, colmVal.toString());
            } else {
                idFieldsMod.put(column, _field);
            }

        }
        return idFieldsMod;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public LockModeType getLockMode() {
        throw new UnsupportedOperationException("Locking is not supported in native queries");
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public int getMaxResults() {
        return this.maxResults;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeParameter<?> getParameter(int position) {
        return this.parameters.get(position);
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public <T> Parameter<T> getParameter(int position, Class<T> type) {
        throw new NotImplementedException("Native queries do not define parameter types. Use getParameter(int)");
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeParameter<?> getParameter(String name) {
        // JSR-317 3.8.15 >> The use of named parameters is not defined for native queries.
        throw new NotImplementedException("Native queries do not support named parameters.");
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public <T> Parameter<T> getParameter(String name, Class<T> type) {
        // JSR-317 3.8.15 >> The use of named parameters is not defined for native queries.
        throw new NotImplementedException("Native queries do not support named parameters.");
    }

    @SuppressWarnings("rawtypes")
    private NativeParameter<?> getParameter0(int position) {
        final NativeParameter<?> parameter = this.getParameter(position);
        if (parameter != null) {
            return this.parameters.get(position);
        } else {
            return this.parameters.put(position, new NativeParameter(position));
        }
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public Set<Parameter<?>> getParameters() {
        final Set<Parameter<?>> parameters = Sets.newHashSet();

        for (final NativeParameter<?> parameter : this.parameters.values()) {
            parameters.add(parameter);
        }

        return parameters;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public Object getParameterValue(int position) {
        return this.parameterValues.get(this.getParameter(position));
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T> T getParameterValue(Parameter<T> param) {
        return (T) this.parameterValues.get(param);
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public Object getParameterValue(String name) {
        // JSR-317 3.8.15 >> The use of named parameters is not defined for native queries.
        throw new NotImplementedException("Native queries do not support named parameters.");
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public List<?> getResultList() {
        if (this.results != null) {
            return this.results;
        }

        return this.getResultListImpl();
    }

    private List<?> getResultListImpl() {
        this.em.getSession().setLoadTracker();

        try {

            final Object[] paramValues = new Object[this.parameters.size()];
            for (int i = 0; i < paramValues.length; i++) {
                paramValues[i] = this.getParameterValue(i + 1);
            }

            try {
                return this.results = new QueryRunner(this.em.getJdbcAdaptor(), false)
                        .query(this.em.getConnection(), this.query, this, paramValues);
            } catch (final SQLException e) {
                throw new PersistenceException("Native query execution failed!", e);
            }
        } finally {
            this.em.getSession().releaseLoadTracker();
        }
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public Object getSingleResult() {
        final List<?> resultList = this.getResultList();

        if (resultList.size() > 1) {
            throw new NonUniqueResultException();
        }

        if (resultList.size() == 0) {
            throw new NoResultException();
        }

        return resultList.get(0);
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public List<Object> handle(ResultSet resultSet) throws SQLException {
        if (this.sqlResultSetMapping != null) {
            return this.handleWithSqlResultSetMapping(resultSet);
        } else if (this.resultClass != null) {// designated return type
            return this.handleWithResultClass(resultSet);
        }
        // last option return query as scalar
        return handleAsScalar(resultSet);
    }

    private List<Object> handleAsScalar(ResultSet resultSet) throws SQLException {
        // handle as scalar or scalar array
        final ArrayList<Object> results = Lists.newArrayList();

        final int columnCount = resultSet.getMetaData().getColumnCount();
        while (resultSet.next()) {
            // single scalar
            if (columnCount == 1) {
                results.add(resultSet.getObject(1));
                continue;
            }

            // array of scalars
            final Object[] result = new Object[columnCount];
            for (int i = 0; i < columnCount; i++) {
                result[i] = resultSet.getObject(i + 1);
            }

            results.add(result);
        }
        return results;
    }

    private ManagedInstance<?> handleInstance(ResultSet row, EntityTypeImpl<?> entityType,
            String discriminatorColumn, HashMap<String, Object> fieldMap) throws SQLException {
        final SessionImpl session = this.em.getSession();

        // get the id of for the instance
        final ManagedId<?> managedId = entityType.getId(session, row,
                this.getIdFieldTransformed(entityType.getPrimaryTable().getIdFields(), fieldMap));

        if (managedId == null) {
            return null;
        }

        // look for it in the session
        ManagedInstance<?> instance = session.get(managedId);

        // if found then return it
        if (instance != null) {
            // if it is a new instance simply return it
            if (!(instance.getInstance() instanceof EnhancedInstance)) {
                return instance;
            }

            final EnhancedInstance enhancedInstance = (EnhancedInstance) instance.getInstance();

            // if it is a lazy instance mark as loading and initialize
            if (!enhancedInstance.__enhanced__$$__isInitialized()) {
                this.initializeInstance(session, row, instance, entityType, fieldMap);

                session.lazyInstanceLoading(instance);
                enhancedInstance.__enhanced__$$__setInitialized();
            }

            return instance;
        }

        // if no inheritance then initialize and return
        if (entityType.getInheritanceType() == null) {
            instance = entityType.getManagedInstanceById(session, (ManagedId) managedId, false);
        }
        // inheritance is in place then locate the correct child type
        else {
            discriminatorColumn = (discriminatorColumn == null) ? entityType.getDiscriminatorColumn().getName()
                    : discriminatorColumn;

            final String discriminatorValue = row.getObject(discriminatorColumn).toString();

            // check if we have a legal discriminator value
            final EntityTypeImpl<?> effectiveType = entityType.getChildType(discriminatorValue);
            if (effectiveType == null) {
                throw new IllegalArgumentException(
                        "Discriminator " + discriminatorValue + " not found in the type " + entityType.getName());
            }

            // initialize and return
            instance = effectiveType.getManagedInstanceById(session, (ManagedId) managedId, false);
        }

        this.initializeInstance(session, row, instance, entityType, fieldMap);
        session.put(instance);

        return instance;
    }

    /**
     * result set handler for a given resultClass
     * 
     * @return result
     * @param resultSet
     * @throws SQLException
     * @since $version
     */
    private List<Object> handleWithResultClass(ResultSet resultSet) throws SQLException {
        final ArrayList<Object> result = Lists.newArrayList();

        final EntityTypeImpl<?> entityType = this.em.getMetamodel().entity(this.resultClass);
        if (entityType == null) {
            throw new PersistenceException("Entity Class is not managed :" + this.resultClass);
        }

        while (resultSet.next()) {// for each row
            final ManagedInstance<?> managedInstance = this.handleInstance(resultSet, entityType, null, null);

            if (managedInstance != null) {
                result.add(managedInstance.getInstance());
            } else {
                result.add(null);
            }
        }
        return result;
    }

    /**
     * result set handler for SqlResultSetMapping annotation data
     * 
     * @return result
     * @param resultSet
     * @throws SQLException
     * @since $version
     */
    private List<Object> handleWithSqlResultSetMapping(ResultSet resultSet) throws SQLException {
        final ArrayList<Object> result = Lists.newArrayList();
        final ArrayList<Object> resultRow = Lists.newArrayList();

        while (resultSet.next()) {// for each row
            for (final EntityResultMetadata entityResultMetadata : this.sqlResultSetMapping.getEntities()) {
                final EntityTypeImpl<?> entityType = this.em.getMetamodel()
                        .entity(entityResultMetadata.getEntityClass());

                if (entityType == null) {
                    throw new PersistenceException(
                            "Entity Class is not managed :" + entityResultMetadata.getEntityClass());
                }

                final HashMap<String, Object> _fieldMap = this.fieldMap.get(entityType.getJavaType().getName());

                final ManagedInstance<?> managedInstance = this.handleInstance(resultSet, entityType,
                        entityResultMetadata.getDiscriminatorColumn(), _fieldMap);

                if (managedInstance != null) {
                    resultRow.add(managedInstance.getInstance());
                } else {
                    resultRow.add(null);
                }
            }
            for (final ColumnResultMetadata columnResultMetadata : this.sqlResultSetMapping.getColumns()) {
                resultRow.add(resultSet.getObject(columnResultMetadata.getName()));
            }
            if (resultRow.size() > 1) {
                result.add(resultRow.toArray());
            } else {
                result.add(resultRow.get(0));
            }
            resultRow.clear();
        }
        return result;
    }

    /**
     * initialize the managedInstance with sql row data and fieldResult Mapping
     * 
     * @param session
     * @param row
     *            Sql data row
     * @param managedInstance
     * @param entityType
     * @param fieldMap
     *            fieldResult Mapping data
     * @throws SQLException
     * @since $version
     */
    private void initializeInstance(SessionImpl session, ResultSet row, ManagedInstance<?> managedInstance,
            EntityTypeImpl<?> entityType, HashMap<String, Object> fieldMap) throws SQLException {
        managedInstance.setLoading(true);

        final Object instance = managedInstance.getInstance();
        for (final AbstractMapping<?, ?, ?> mapping : entityType.getMappingsSingular()) {

            if (mapping instanceof BasicMappingImpl) {
                final BasicMappingImpl<?, ?> basicMapping = (BasicMappingImpl<?, ?>) mapping;
                final BasicColumn column = basicMapping.getColumn();

                final String colName = (fieldMap != null && fieldMap.get(basicMapping.getName()) != null) ? //
                        fieldMap.get(basicMapping.getName()).toString() : column.getName();

                column.setValue(instance, row.getObject(colName));
            } else if (mapping instanceof SingularAssociationMappingImpl) {
                final SingularAssociationMappingImpl<?, ?> singularAssociationMapping = (SingularAssociationMappingImpl<?, ?>) mapping;
                final EntityTypeImpl<?> singularChildType = ((SingularAssociationMappingImpl<?, ?>) mapping)
                        .getType();

                final HashMap<String, Object> _parentFieldMap = this.fieldMap
                        .get(singularAssociationMapping.getParent().getJavaType().getName());

                final SingularMappingEx<?, ?> idMapping = singularChildType.getIdMapping();

                if (singularChildType.hasSingleIdAttribute() && idMapping instanceof BasicMappingImpl) {

                    final Object colnameTemp = (_parentFieldMap != null)
                            ? _parentFieldMap.get(singularAssociationMapping.getName())
                            : null;

                    final String colname = colnameTemp == null
                            ? ((BasicMappingImpl) idMapping).getColumn().getName()
                            : colnameTemp.toString();

                    final Object _id = row.getObject(colname);

                    if (_id != null) {
                        final Object reference = session.getEntityManager()
                                .getReference(singularChildType.getJavaType(), _id);
                        mapping.set(instance, reference);
                        managedInstance.setJoinLoaded(singularAssociationMapping);
                    }
                } else {
                    final IdModel idModel = (IdModel) _parentFieldMap.get(singularAssociationMapping.getName());
                    final HashMap<String, Object> _parentIdFieldMap = idModel.getIdMap();

                    if (idMapping instanceof EmbeddedMappingImpl) {
                        // TODO should we test embeddedId attr name, or just waste of cpu???
                        final String embeddedIdName = ((EmbeddedMappingImpl) idMapping).getAttribute().getName();
                        final String embeddedId = idModel.getEmbeddedId();
                        if (!embeddedIdName.equals(embeddedId)) {
                            // wrong fieldMapping conf just return
                            return;
                        }
                    }
                    final ManagedInstance<?> handleInstance = this.handleInstance(row, singularChildType, null,
                            _parentIdFieldMap);

                    mapping.set(instance, handleInstance.getInstance());
                    managedInstance.setJoinLoaded(singularAssociationMapping);

                    session.lazyInstanceLoading(handleInstance);
                }
            }
        }
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public boolean isBound(Parameter<?> param) {
        return this.getParameterValue(param) != null;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setFirstResult(int startPosition) {
        this.firstResult = startPosition;

        return this;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setFlushMode(FlushModeType flushMode) {
        this.flushMode = flushMode;

        return this;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setHint(String hintName, Object value) {
        this.hints.put(hintName, value);

        return this;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setLockMode(LockModeType lockMode) {
        throw new UnsupportedOperationException("Locking is not supported in native queries");
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setMaxResults(int maxResults) {
        this.maxResults = maxResults;

        return this;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setParameter(int position, Calendar value, TemporalType temporalType) {
        this.parameterValues.put(this.getParameter0(position), this.convertTemporal(temporalType, value));

        return this;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setParameter(int position, Date value, TemporalType temporalType) {
        this.parameterValues.put(this.getParameter0(position), this.convertTemporal(temporalType, value));

        return this;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setParameter(int position, Object value) {
        this.parameterValues.put(this.getParameter0(position), value);

        return this;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType) {
        this.parameterValues.put(this.getParameter0(param.getPosition()),
                this.convertTemporal(temporalType, value));

        return this;

    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setParameter(Parameter<Date> param, Date value, TemporalType temporalType) {
        this.parameterValues.put(this.getParameter0(param.getPosition()),
                this.convertTemporal(temporalType, value));

        return this;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public <T> NativeQuery setParameter(Parameter<T> param, T value) {
        this.parameterValues.put(this.getParameter0(param.getPosition()), value);

        return this;
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setParameter(String name, Calendar value, TemporalType temporalType) {
        // JSR-317 3.8.15 >> The use of named parameters is not defined for native queries.
        throw new NotImplementedException("Native queries do not support named parameters.");
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setParameter(String name, Date value, TemporalType temporalType) {
        // JSR-317 3.8.15 >> The use of named parameters is not defined for native queries.
        throw new NotImplementedException("Native queries do not support named parameters.");
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public NativeQuery setParameter(String name, Object value) {
        // JSR-317 3.8.15 >> The use of named parameters is not defined for native queries.
        throw new NotImplementedException("Native queries do not support named parameters.");
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public <T> T unwrap(Class<T> cls) {
        return null;
    }
}