alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (CacheableResultTransformer.java)

This example Hibernate source code file (CacheableResultTransformer.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

cacheableresulttransformer, cacheableresulttransformer, illegalargumentexception, illegalargumentexception, illegalstateexception, list, object, override, reflection, resulttransformer, string, string, t, t, tuplesubsetresulttransformer, util

The Hibernate CacheableResultTransformer.java source code

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2010, Red Hat Middleware LLC or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Middleware LLC.
 *
 * 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.hibernate.transform;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.type.Type;

/**
 * A ResultTransformer that is used to transfor tuples to a value(s)
 * that can be cached.
 *
 * @author Gail Badner
 */
public class CacheableResultTransformer implements ResultTransformer {

	// would be nice to be able to have this class extend
	// PassThroughResultTransformer, but the default constructor
	// is private (as it should be for a singleton)
	private final static PassThroughResultTransformer ACTUAL_TRANSFORMER =
			PassThroughResultTransformer.INSTANCE;
	private final int tupleLength;
	private final int tupleSubsetLength;

	// array with the i-th element indicating whether the i-th
	// expression returned by a query is included in the tuple;
	// IMPLLEMENTATION NOTE:
	// "joined" and "fetched" associations may use the same SQL,
	// but result in different tuple and cached values. This is
	// because "fetched" associations are excluded from the tuple.
	//  includeInTuple provides a way to distinguish these 2 cases.
	private final boolean[] includeInTuple;

	// indexes for tuple that are included in the transformation;
	// set to null if all elements in the tuple are included
	private final int[] includeInTransformIndex;

	/**
	 * Returns a CacheableResultTransformer that is used to transform
	 * tuples to a value(s) that can be cached.
	 *
	 * @param transformer - result transformer that will ultimately be
	 *        be used (after caching results)
	 * @param aliases - the aliases that correspond to the tuple;
	 *        if it is non-null, its length must equal the number
	 *        of true elements in includeInTuple[]
	 * @param includeInTuple - array with the i-th element indicating
	 *        whether the i-th expression returned by a query is
	 *        included in the tuple; the number of true values equals
	 *        the length of the tuple that will be transformed;
	 *        must be non-null
	 * @return a CacheableResultTransformer that is used to transform
	 *         tuples to a value(s) that can be cached.
	 */
	public static CacheableResultTransformer create(ResultTransformer transformer,
													String[] aliases,
													boolean[] includeInTuple) {
		return transformer instanceof TupleSubsetResultTransformer ?
				create( ( TupleSubsetResultTransformer ) transformer, aliases, includeInTuple ) :
				create( includeInTuple )
		;
	}

	/**
	 * Returns a CacheableResultTransformer that is used to transform
	 * tuples to a value(s) that can be cached.
	 *
	 * @param transformer - a tuple subset result transformer;
	 *        must be non-null;
	 * @param aliases - the aliases that correspond to the tuple;
	 *        if it is non-null, its length must equal the number
	 *        of true elements in includeInTuple[]
	 * @param includeInTuple - array with the i-th element indicating
	 *        whether the i-th expression returned by a query is
	 *        included in the tuple; the number of true values equals
	 *        the length of the tuple that will be transformed;
	 *        must be non-null
	 * @return a CacheableResultTransformer that is used to transform
	 *         tuples to a value(s) that can be cached.
	 */
	private static CacheableResultTransformer create(TupleSubsetResultTransformer transformer,
													 String[] aliases,
													 boolean[] includeInTuple) {
		if ( transformer == null ) {
			throw new IllegalArgumentException( "transformer cannot be null" );
		}
		int tupleLength = ArrayHelper.countTrue( includeInTuple );
		if ( aliases != null && aliases.length != tupleLength ) {
			throw new IllegalArgumentException(
					"if aliases is not null, then the length of aliases[] must equal the number of true elements in includeInTuple; " +
							"aliases.length=" + aliases.length + "tupleLength=" + tupleLength
			);
		}
		return new CacheableResultTransformer(
				includeInTuple,
				transformer.includeInTransform( aliases, tupleLength )
		);
	}

	/**
	 * Returns a CacheableResultTransformer that is used to transform
	 * tuples to a value(s) that can be cached.
	 *
	 * @param includeInTuple - array with the i-th element indicating
	 *        whether the i-th expression returned by a query is
	 *        included in the tuple; the number of true values equals
	 *        the length of the tuple that will be transformed;
	 *        must be non-null
	 * @return a CacheableResultTransformer that is used to transform
	 *         tuples to a value(s) that can be cached.
	 */
	private static CacheableResultTransformer create(boolean[] includeInTuple) {
		return new CacheableResultTransformer( includeInTuple, null );
	}

	private CacheableResultTransformer(boolean[] includeInTuple, boolean[] includeInTransform) {
		if ( includeInTuple == null ) {
			throw new IllegalArgumentException( "includeInTuple cannot be null" );
		}
		this.includeInTuple = includeInTuple;
		tupleLength = ArrayHelper.countTrue( includeInTuple );
		tupleSubsetLength = (
				includeInTransform == null ?
						tupleLength :
						ArrayHelper.countTrue( includeInTransform )
		);
		if ( tupleSubsetLength == tupleLength ) {
			includeInTransformIndex = null;
		}
		else {
			includeInTransformIndex = new int[tupleSubsetLength];
			for ( int i = 0, j = 0 ; i < includeInTransform.length ; i++ ) {
				if ( includeInTransform[ i ] ) {
					includeInTransformIndex[ j ] =  i;
					j++;
				}
			}
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public Object transformTuple(Object[] tuple, String aliases[]) {
		if ( aliases != null && aliases.length != tupleLength ) {
			throw new IllegalStateException(
					"aliases expected length is " + tupleLength +
					"; actual length is " + aliases.length );
		}
		// really more correct to pass index( aliases.getClass(), aliases )
		// as the 2nd arg to the following statement;
		// passing null instead because it ends up being ignored.
		return ACTUAL_TRANSFORMER.transformTuple( index( tuple.getClass(), tuple ), null );
	}

	/**
	 * Re-transforms, if necessary, a List of values previously
	 * transformed by this (or an equivalent) CacheableResultTransformer.
	 * Each element of the list is re-transformed in place (i.e, List
	 * elements are replaced with re-transformed values) and the original
	 * List is returned.
	 * <p/>
	 * If re-transformation is unnecessary, the original List is returned
	 * unchanged.
	 *
	 * @param transformedResults - results that were previously transformed
	 * @param aliases - the aliases that correspond to the untransformed tuple;
	 * @param transformer - the transformer for the re-transformation
	 * @return transformedResults, with each element re-transformed (if nececessary)
	 */
	public List retransformResults(List transformedResults,
								   String aliases[],
								   ResultTransformer transformer,
								   boolean[] includeInTuple) {
		if ( transformer == null ) {
			throw new IllegalArgumentException( "transformer cannot be null" );
		}
		if ( ! this.equals( create( transformer, aliases, includeInTuple ) ) ) {
			throw new IllegalStateException(
					"this CacheableResultTransformer is inconsistent with specified arguments; cannot re-transform"
			);
		}
		boolean requiresRetransform = true;
		String[] aliasesToUse = aliases == null ? null : index( ( aliases.getClass() ), aliases );
		if ( transformer == ACTUAL_TRANSFORMER ) {
			requiresRetransform = false;
		}
		else if ( transformer instanceof TupleSubsetResultTransformer ) {
			requiresRetransform =  ! ( ( TupleSubsetResultTransformer ) transformer ).isTransformedValueATupleElement(
					aliasesToUse,
					tupleLength
			);
		}
		if ( requiresRetransform ) {
			for ( int i = 0 ; i < transformedResults.size() ; i++ ) {
				Object[] tuple = ACTUAL_TRANSFORMER.untransformToTuple(
									transformedResults.get( i ),
									tupleSubsetLength == 1
				);
				transformedResults.set( i, transformer.transformTuple( tuple, aliasesToUse ) );
			}
		}
		return transformedResults;
	}

	/**
	 * Untransforms, if necessary, a List of values previously
	 * transformed by this (or an equivalent) CacheableResultTransformer.
	 * Each element of the list is untransformed in place (i.e, List
	 * elements are replaced with untransformed values) and the original
	 * List is returned.
	 * <p/>
	 * If not unnecessary, the original List is returned
	 * unchanged.
	 * <p/>
	 * NOTE: If transformed values are a subset of the original
	 *       tuple, then, on return, elements corresponding to
	 *       excluded tuple elements will be null.
	 * @param results - results that were previously transformed
	 * @return results, with each element untransformed (if nececessary)
	 */
	public List untransformToTuples(List results) {
		if ( includeInTransformIndex == null ) {
			results = ACTUAL_TRANSFORMER.untransformToTuples(
					results,
					tupleSubsetLength == 1
			);
		}
		else {
			for ( int i = 0 ; i < results.size() ; i++ ) {
				Object[] tuple = ACTUAL_TRANSFORMER.untransformToTuple(
									results.get( i ),
									tupleSubsetLength == 1
				);
				results.set( i, unindex( tuple.getClass(), tuple ) );
			}

		}
		return results;
	}

	/**
	 * Returns the result types for the transformed value.
	 * @param tupleResultTypes
	 * @return
	 */
	public Type[] getCachedResultTypes(Type[] tupleResultTypes) {
		return tupleLength != tupleSubsetLength ?
				index( tupleResultTypes.getClass(), tupleResultTypes ) :
				tupleResultTypes
		;
	}

	/**
	 * {@inheritDoc}
	 */
	public List transformList(List list) {
		return list;
	}

	private <T> T[] index(Class clazz, T[] objects) {
		T[] objectsIndexed = objects;
		if ( objects != null &&
				includeInTransformIndex != null &&
				objects.length != tupleSubsetLength ) {
			objectsIndexed = clazz.cast( Array.newInstance( clazz.getComponentType(), tupleSubsetLength ) );
			for ( int i = 0 ; i < tupleSubsetLength; i++ ) {
				objectsIndexed[ i ] = objects[ includeInTransformIndex[ i ] ];
			}
		}
		return objectsIndexed;
	}

	private <T> T[] unindex(Class clazz, T[] objects) {
		T[] objectsUnindexed = objects;
		if ( objects != null &&
				includeInTransformIndex != null &&
				objects.length != tupleLength ) {
			objectsUnindexed = clazz.cast( Array.newInstance( clazz.getComponentType(), tupleLength ) );
			for ( int i = 0 ; i < tupleSubsetLength; i++ ) {
				objectsUnindexed[ includeInTransformIndex[ i ] ] = objects[ i ];
			}
		}
		return objectsUnindexed;
	}

	@Override
	public boolean equals(Object o) {
		if ( this == o ) {
			return true;
		}
		if ( o == null || getClass() != o.getClass() ) {
			return false;
		}

		CacheableResultTransformer that = ( CacheableResultTransformer ) o;

		if ( tupleLength != that.tupleLength ) {
			return false;
		}
		if ( tupleSubsetLength != that.tupleSubsetLength ) {
			return false;
		}
		if ( !Arrays.equals( includeInTuple, that.includeInTuple ) ) {
			return false;
		}
		if ( !Arrays.equals( includeInTransformIndex, that.includeInTransformIndex ) ) {
			return false;
		}

		return true;
	}

	@Override
	public int hashCode() {
		int result = tupleLength;
		result = 31 * result + tupleSubsetLength;
		result = 31 * result + ( includeInTuple != null ? Arrays.hashCode( includeInTuple ) : 0 );
		result = 31 * result + ( includeInTransformIndex != null ? Arrays.hashCode( includeInTransformIndex ) : 0 );
		return result;
	}
}

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate CacheableResultTransformer.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.