miscellaneous code cleanups

This commit is contained in:
Gavin King 2024-11-13 23:09:24 +01:00
parent 9d30d210ed
commit dd858e3dbf
12 changed files with 294 additions and 376 deletions

View File

@ -154,7 +154,7 @@ public interface NaturalIdLoadAccess<T> {
* @deprecated use {@link #using(Map)} with {@link Map#of}, which is
* slightly more typesafe
*/
@Deprecated(since = "6.3")
@Deprecated(since = "6.3", forRemoval = true)
NaturalIdLoadAccess<T> using(Object... mappings);
/**

View File

@ -4,13 +4,13 @@
*/
package org.hibernate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.RootGraph;
import static org.hibernate.internal.util.collections.CollectionHelper.asMap;
import org.hibernate.internal.util.collections.CollectionHelper;
/**
* Loads multiple instances of a given entity type at once, by
@ -184,8 +184,17 @@ public interface NaturalIdMultiLoadAccess<T> {
*
* @deprecated use {@link Map#of} instead
*/
@Deprecated(since = "6.3")
@Deprecated(since = "6.3", forRemoval = true)
static Map<String,?> compoundValue(Object... elements) {
return asMap( elements );
assert elements != null;
assert elements.length % 2 == 0;
final HashMap<String, Object> map = new HashMap<>();
CollectionHelper.collectMapEntries( map::put, elements );
for ( int i = 0; i < elements.length; i += 2 ) {
map.put( (String) elements[ i ], (Object) elements[ i+1 ] );
}
return map;
}
}

View File

@ -43,7 +43,6 @@ import org.hibernate.id.uuid.UuidValueGenerator;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.GeneratorCreator;
import org.hibernate.mapping.KeyValue;
import org.hibernate.mapping.PersistentClass;
@ -74,6 +73,7 @@ import static org.hibernate.boot.model.internal.GeneratorStrategies.generatorCla
import static org.hibernate.id.IdentifierGenerator.GENERATOR_NAME;
import static org.hibernate.internal.util.NullnessUtil.castNonNull;
import static org.hibernate.internal.util.StringHelper.qualify;
import static org.hibernate.internal.util.collections.CollectionHelper.combineUntyped;
import static org.hibernate.resource.beans.internal.Helper.allowExtensionsInCdi;
/**
@ -883,7 +883,7 @@ public class GeneratorBinder {
Locale.ROOT,
"Identifier attribute '%s' has too many generator annotations: %s",
getPath( propertyHolder, inferredData ),
CollectionHelper.combineUntyped( idGeneratorAnnotations, generatorAnnotations )
combineUntyped( idGeneratorAnnotations, generatorAnnotations )
) );
}
if ( !idGeneratorAnnotations.isEmpty() ) {

View File

@ -5,7 +5,6 @@
package org.hibernate.internal.util.collections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@ -20,6 +19,14 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.Function;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
/**
* Various helper util methods for handling collections.
*
@ -130,7 +137,7 @@ public final class CollectionHelper {
*
* @return The proper size.
*/
public static int determineProperSizing(Map original) {
public static int determineProperSizing(Map<?,?> original) {
return determineProperSizing( original.size() );
}
@ -147,17 +154,12 @@ public final class CollectionHelper {
if ( original == null ) {
return null;
}
final HashMap<K, V> copy = new HashMap<>( determineProperSizing( original ) );
original.forEach(
(key, value) -> copy.put(
keyTransformer.apply( key ),
valueTransformer.apply( value )
)
);
return copy;
else {
final HashMap<K, V> copy = new HashMap<>( determineProperSizing( original ) );
original.forEach( (key, value) -> copy.put( keyTransformer.apply( key ),
valueTransformer.apply( value ) ) );
return copy;
}
}
public static <K, V> Map<K, V> makeMap(
@ -171,19 +173,15 @@ public final class CollectionHelper {
Function<E,K> keyProducer,
Function<E,V> valueProducer) {
if ( isEmpty( collection ) ) {
return Collections.emptyMap();
return emptyMap();
}
final Map<K, V> map = new HashMap<>( determineProperSizing( collection.size() ));
for ( E element : collection ) {
map.put(
keyProducer.apply( element ),
valueProducer.apply( element )
);
else {
final Map<K, V> map = new HashMap<>( determineProperSizing( collection.size() ) );
for ( E element : collection ) {
map.put( keyProducer.apply( element ), valueProducer.apply( element ) );
}
return map;
}
return map;
}
/**
@ -194,7 +192,7 @@ public final class CollectionHelper {
*
* @return The proper size.
*/
public static int determineProperSizing(Set original) {
public static int determineProperSizing(Set<?> original) {
return determineProperSizing( original.size() );
}
@ -207,8 +205,7 @@ public final class CollectionHelper {
* @return The proper size.
*/
public static int determineProperSizing(int numberOfElements) {
int actual = ( (int) ( numberOfElements / LOAD_FACTOR ) ) + 1;
return Math.max( actual, MINIMUM_INITIAL_CAPACITY );
return Math.max( ( (int) ( numberOfElements / LOAD_FACTOR ) ) + 1, MINIMUM_INITIAL_CAPACITY );
}
/**
@ -255,26 +252,26 @@ public final class CollectionHelper {
if ( source == null ) {
return null;
}
final int size = source.size();
final Set<T> copy = CollectionHelper.setOfSize( size + 1 );
copy.addAll( source );
return copy;
else {
final Set<T> copy = setOfSize( source.size() + 1 );
copy.addAll( source );
return copy;
}
}
public static boolean isEmpty(Collection<?> collection) {
return collection == null || collection.isEmpty();
}
public static boolean isEmpty(Map map) {
public static boolean isEmpty(Map<?,?> map) {
return map == null || map.isEmpty();
}
public static boolean isNotEmpty(Collection collection) {
public static boolean isNotEmpty(Collection<?> collection) {
return !isEmpty( collection );
}
public static boolean isNotEmpty(Map map) {
public static boolean isNotEmpty(Map<?,?> map) {
return !isEmpty( map );
}
@ -305,23 +302,20 @@ public final class CollectionHelper {
}
public static <T> Set<T> setOf(Collection<T> values) {
if ( isEmpty( values ) ) {
return Collections.emptySet();
}
return new HashSet<>( values );
return isEmpty( values ) ? emptySet() : new HashSet<>( values );
}
public static Properties asProperties(Map<?,?> map) {
if ( map instanceof Properties ) {
return ( (Properties) map );
if ( map instanceof Properties properties ) {
return properties;
}
final Properties properties = new Properties();
if ( isNotEmpty( map ) ) {
properties.putAll( map );
else {
final Properties properties = new Properties();
if ( isNotEmpty( map ) ) {
properties.putAll( map );
}
return properties;
}
return properties;
}
/**
@ -335,9 +329,9 @@ public final class CollectionHelper {
public static <T> Set<T> toSmallSet(Set<T> set) {
switch ( set.size() ) {
case 0:
return Collections.EMPTY_SET;
return emptySet();
case 1:
return Collections.singleton( set.iterator().next() );
return singleton( set.iterator().next() );
default:
//TODO assert tests pass even if this is set to return an unmodifiable Set
return set;
@ -354,10 +348,10 @@ public final class CollectionHelper {
public static <K, V> Map<K, V> toSmallMap(final Map<K, V> map) {
switch ( map.size() ) {
case 0:
return Collections.EMPTY_MAP;
return emptyMap();
case 1:
Map.Entry<K, V> entry = map.entrySet().iterator().next();
return Collections.singletonMap( entry.getKey(), entry.getValue() );
return singletonMap( entry.getKey(), entry.getValue() );
default:
//TODO assert tests pass even if this is set to return an unmodifiable Map
return map;
@ -374,15 +368,16 @@ public final class CollectionHelper {
public static <V> List<V> toSmallList(ArrayList<V> arrayList) {
switch ( arrayList.size() ) {
case 0:
return Collections.EMPTY_LIST;
return emptyList();
case 1:
return Collections.singletonList( arrayList.get( 0 ) );
return singletonList( arrayList.get( 0 ) );
default:
arrayList.trimToSize();
return arrayList;
}
}
@Deprecated(forRemoval = true)
@SuppressWarnings( "unchecked" )
public static <K,V> void collectMapEntries(BiConsumer<K, V> mapEntryConsumer, Object[] mappings) {
// even numbered
@ -393,96 +388,6 @@ public final class CollectionHelper {
}
}
@SuppressWarnings( "unchecked" )
public static <K,S> Map<K, S> asMap(Object[] elements) {
assert elements != null;
assert elements.length % 2 == 0;
final HashMap<K,S> map = new HashMap<>();
collectMapEntries( map::put, elements );
for ( int i = 0; i < elements.length; i += 2 ) {
map.put( (K) elements[ i ], (S) elements[ i+1 ] );
}
return map;
}
public static Map<String,String> toMap(String... pairs) {
assert pairs.length % 2 == 0;
if ( pairs.length == 2 ) {
return Collections.singletonMap( pairs[0], pairs[1] );
}
final Map<String,String> result = new HashMap<>();
applyToMap( result, pairs );
return result;
}
private static void applyToMap(Map<String,String> map, String... pairs) {
assert pairs.length % 2 == 0;
for ( int i = 0; i < pairs.length; i+=2 ) {
map.put( pairs[i], pairs[i+1] );
}
}
public static Map<String,?> toMap(Object... pairs) {
assert pairs.length % 2 == 0;
if ( pairs.length == 2 ) {
return Collections.singletonMap( (String) pairs[0], pairs[1] );
}
final Map<String,String> result = new HashMap<>();
applyToMap( result, pairs );
return result;
}
public static Map<String,Object> toSettingsMap(Object... pairs) {
assert pairs.length % 2 == 0;
if ( pairs.length == 2 ) {
return Collections.singletonMap( (String) pairs[0], pairs[1] );
}
final Map<String,Object> result = new HashMap<>();
applyToMap( result, pairs );
return result;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static void applyToMap(Map<String,?> map, Object... pairs) {
assert pairs.length % 2 == 0;
for ( int i = 0; i < pairs.length; i+=2 ) {
( (Map) map ).put( pairs[i], pairs[i+1] );
}
}
public static String[] asPairs(Map<String,String> map) {
final String[] pairs = new String[ map.size() * 2 ];
int i = 0;
for ( Map.Entry<String,String> entry : map.entrySet() ) {
pairs[i++] = entry.getKey();
pairs[i++] = entry.getValue();
}
return pairs;
}
public static Properties toProperties(Object... pairs) {
final Properties properties = new Properties();
if ( pairs.length > 0 ) {
assert pairs.length % 2 == 0;
for ( int i = 0; i < pairs.length; i+=2 ) {
properties.put( pairs[i], pairs[i+1] );
}
}
return properties;
}
public static void applyToProperties(Properties properties, Object... pairs) {
assert pairs.length % 2 == 0;
for ( int i = 0; i < pairs.length; i+=2 ) {
properties.put( pairs[i], pairs[i+1] );
}
}
public static <O> List<O> combine(List<O> list1, List<O> list2) {
final ArrayList<O> combined = arrayList( list1.size() + list2.size() );
combined.addAll( list1 );
@ -498,10 +403,11 @@ public final class CollectionHelper {
return combined;
}
@SafeVarargs
public static <O> List<O> combine(List<O>... lists) {
final ArrayList<O> combined = new ArrayList<>();
for ( int i = 0; i < lists.length; i++ ) {
combined.addAll( lists[i] );
for ( List<O> list : lists ) {
combined.addAll( list );
}
return combined;
}
@ -518,10 +424,11 @@ public final class CollectionHelper {
return values == null ? 0 : values.size();
}
@SafeVarargs
public static <X> Set<X> toSet(X... values) {
final HashSet<X> result = new HashSet<>();
if ( isNotEmpty( values ) ) {
result.addAll( Arrays.asList( values ) );
result.addAll( asList( values ) );
}
return result;
}
@ -532,16 +439,19 @@ public final class CollectionHelper {
if ( totalCount == 0 ) {
return new ArrayList<>();
}
final ArrayList<E> joined = new ArrayList<>( totalCount );
if ( first != null ) {
joined.addAll( first );
else {
final ArrayList<E> joined = new ArrayList<>( totalCount );
if ( first != null ) {
joined.addAll( first );
}
if ( second != null ) {
joined.addAll( second );
}
return joined;
}
if ( second != null ) {
joined.addAll( second );
}
return joined;
}
@SafeVarargs
public static <E> List<E> mutableJoin(Collection<E> first, Collection<E>... others) {
// it can be empty, but not null
assert first != null;

View File

@ -49,7 +49,7 @@ public class NaturalIdLoadAccessImpl<T> extends BaseNaturalIdLoadAccessImpl<T> i
return this;
}
@Override @Deprecated
@Override @Deprecated(forRemoval = true)
public NaturalIdLoadAccess<T> using(Object... mappings) {
CollectionHelper.collectMapEntries( naturalIdParameters::put, mappings );
return this;

View File

@ -8,7 +8,6 @@ import java.io.Serializable;
import java.time.Instant;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
@ -20,11 +19,11 @@ import java.util.function.Supplier;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.query.QueryFlushMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.ScrollMode;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.query.spi.NativeQueryInterpreter;
@ -35,11 +34,8 @@ import org.hibernate.graph.RootGraph;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.AbstractSharedSessionContract;
import org.hibernate.internal.util.MathHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.spi.NativeQueryTupleTransformer;
import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.BindableType;
import org.hibernate.query.KeyedPage;
import org.hibernate.query.KeyedResultList;
@ -55,6 +51,7 @@ import org.hibernate.query.internal.DelegatingDomainQueryExecutionContext;
import org.hibernate.query.internal.ParameterMetadataImpl;
import org.hibernate.query.internal.QueryOptionsImpl;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.results.Builders;
import org.hibernate.query.results.ResultBuilder;
@ -72,7 +69,6 @@ import org.hibernate.query.spi.DomainQueryExecutionContext;
import org.hibernate.query.spi.MutableQueryOptions;
import org.hibernate.query.spi.NonSelectQueryPlan;
import org.hibernate.query.spi.ParameterMetadataImplementor;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryInterpretationCache;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBinding;
@ -90,7 +86,6 @@ import org.hibernate.query.sql.spi.ParameterOccurrence;
import org.hibernate.query.sql.spi.SelectInterpretationsKey;
import org.hibernate.sql.exec.internal.CallbackImpl;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
import org.hibernate.sql.results.spi.SingleResultConsumer;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.BasicType;
@ -109,9 +104,18 @@ import jakarta.persistence.TemporalType;
import jakarta.persistence.Tuple;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.metamodel.SingularAttribute;
import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
import static java.lang.Character.isWhitespace;
import static java.util.Collections.addAll;
import static org.hibernate.internal.util.StringHelper.unqualify;
import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty;
import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty;
import static org.hibernate.internal.util.collections.CollectionHelper.makeCopy;
import static org.hibernate.jpa.HibernateHints.HINT_NATIVE_LOCK_MODE;
import static org.hibernate.query.results.Builders.resultClassBuilder;
import static org.hibernate.query.results.ResultSetMapping.resolveResultSetMapping;
/**
* @author Steve Ebersole
@ -142,22 +146,12 @@ public class NativeQueryImpl<R>
SharedSessionContractImplementor session) {
this(
memento,
() -> {
if ( memento.getResultMappingName() != null ) {
return buildResultSetMapping( memento.getResultMappingName(), false, session );
}
else if ( memento.getResultType() != null ) {
return buildResultSetMapping( memento.getResultType().getName(), false, session );
}
return buildResultSetMapping( memento.getSqlString(), false, session );
},
() -> buildResultSetMapping( getResultSetMappingName( memento ), false, session ),
(resultSetMapping, querySpaceConsumer, context ) -> {
if ( memento.getResultMappingName() != null ) {
final NamedResultSetMappingMemento resultSetMappingMemento = session.getFactory()
.getQueryEngine()
.getNamedObjectRepository()
.getResultSetMappingMemento( memento.getResultMappingName() );
final NamedResultSetMappingMemento resultSetMappingMemento =
getNamedObjectRepository( session )
.getResultSetMappingMemento( memento.getResultMappingName() );
if ( resultSetMappingMemento != null ) {
resultSetMappingMemento.resolve( resultSetMapping, querySpaceConsumer, context );
return true;
@ -165,21 +159,33 @@ public class NativeQueryImpl<R>
}
if ( memento.getResultType() != null ) {
resultSetMapping.addResultBuilder(
resultClassBuilder(
memento.getResultType(),
context
)
);
resultSetMapping.addResultBuilder( resultClassBuilder( memento.getResultType(), context ) );
return true;
}
return false;
else {
return false;
}
},
session
);
}
private static NamedObjectRepository getNamedObjectRepository(SharedSessionContractImplementor session) {
return session.getFactory().getQueryEngine().getNamedObjectRepository();
}
private static String getResultSetMappingName(NamedNativeQueryMemento<?> memento) {
if ( memento.getResultMappingName() != null ) {
return memento.getResultMappingName();
}
else if ( memento.getResultType() != null ) {
return memento.getResultType().getName();
}
else {
return memento.getSqlString();
}
}
/**
* Constructs a NativeQueryImpl given a sql query defined in the mappings.
*/
@ -195,10 +201,9 @@ public class NativeQueryImpl<R>
},
(resultSetMapping, querySpaceConsumer, context) -> {
if ( memento.getResultMappingName() != null ) {
final NamedResultSetMappingMemento resultSetMappingMemento = session.getFactory()
.getQueryEngine()
.getNamedObjectRepository()
.getResultSetMappingMemento( memento.getResultMappingName() );
final NamedResultSetMappingMemento resultSetMappingMemento =
getNamedObjectRepository( session )
.getResultSetMappingMemento( memento.getResultMappingName() );
if ( resultSetMappingMemento != null ) {
resultSetMappingMemento.resolve( resultSetMapping, querySpaceConsumer, context );
return true;
@ -206,14 +211,12 @@ public class NativeQueryImpl<R>
}
if ( memento.getResultType() != null ) {
resultSetMapping.addResultBuilder( resultClassBuilder(
memento.getResultType(),
context
) );
resultSetMapping.addResultBuilder( resultClassBuilder( memento.getResultType(), context ) );
return true;
}
return false;
else {
return false;
}
},
session
);
@ -223,19 +226,16 @@ public class NativeQueryImpl<R>
}
else if ( resultJavaType != null && !resultJavaType.isArray() ) {
switch ( resultSetMapping.getNumberOfResultBuilders() ) {
case 0: {
case 0:
throw new IllegalArgumentException( "Named query exists, but did not specify a resultClass" );
}
case 1: {
case 1:
final Class<?> actualResultJavaType = resultSetMapping.getResultBuilders().get( 0 ).getJavaType();
if ( actualResultJavaType != null && !resultJavaType.isAssignableFrom( actualResultJavaType ) ) {
throw buildIncompatibleException( resultJavaType, actualResultJavaType );
}
break;
}
default: {
default:
throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" );
}
}
}
}
@ -251,10 +251,9 @@ public class NativeQueryImpl<R>
memento,
() -> buildResultSetMapping( resultSetMappingName, false, session ),
(resultSetMapping, querySpaceConsumer, context) -> {
final NamedResultSetMappingMemento mappingMemento = session.getFactory()
.getQueryEngine()
.getNamedObjectRepository()
.getResultSetMappingMemento( resultSetMappingName );
final NamedResultSetMappingMemento mappingMemento =
getNamedObjectRepository( session )
.getResultSetMappingMemento( resultSetMappingName );
assert mappingMemento != null;
mappingMemento.resolve( resultSetMapping, querySpaceConsumer, context );
return true;
@ -273,10 +272,8 @@ public class NativeQueryImpl<R>
this.originalSqlString = memento.getOriginalSqlString();
final ParameterInterpretation parameterInterpretation = resolveParameterInterpretation(
originalSqlString,
session
);
final ParameterInterpretation parameterInterpretation =
resolveParameterInterpretation( originalSqlString, session );
this.sqlString = parameterInterpretation.getAdjustedSqlString();
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
@ -286,14 +283,8 @@ public class NativeQueryImpl<R>
this.resultSetMapping = resultSetMappingCreator.get();
//noinspection UnnecessaryLocalVariable
final boolean appliedAnyResults = resultSetMappingHandler.resolveResultSetMapping(
resultSetMapping,
querySpaces::add,
this
);
this.resultMappingSuppliedToCtor = appliedAnyResults;
this.resultMappingSuppliedToCtor =
resultSetMappingHandler.resolveResultSetMapping( resultSetMapping, querySpaces::add, this );
applyOptions( memento );
}
@ -304,9 +295,8 @@ public class NativeQueryImpl<R>
AbstractSharedSessionContract session) {
super( session );
final ParameterInterpretation parameterInterpretation = resolveParameterInterpretation( sqlString, session );
this.originalSqlString = sqlString;
final ParameterInterpretation parameterInterpretation = resolveParameterInterpretation( sqlString, session );
this.sqlString = parameterInterpretation.getAdjustedSqlString();
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
this.parameterOccurrences = parameterInterpretation.getOrderedParameterOccurrences();
@ -314,11 +304,7 @@ public class NativeQueryImpl<R>
this.querySpaces = new HashSet<>();
this.resultSetMapping = buildResultSetMapping( resultSetMappingMemento.getName(), false, session );
resultSetMappingMemento.resolve(
resultSetMapping,
this::addSynchronizedQuerySpace,
this
);
resultSetMappingMemento.resolve( resultSetMapping, this::addSynchronizedQuerySpace, this );
this.resultMappingSuppliedToCtor = true;
}
@ -328,14 +314,14 @@ public class NativeQueryImpl<R>
this.querySpaces = new HashSet<>();
final ParameterInterpretation parameterInterpretation = resolveParameterInterpretation( sqlString, session );
this.originalSqlString = sqlString;
final ParameterInterpretation parameterInterpretation = resolveParameterInterpretation( sqlString, session );
this.sqlString = parameterInterpretation.getAdjustedSqlString();
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
this.parameterOccurrences = parameterInterpretation.getOrderedParameterOccurrences();
this.parameterBindings = parameterMetadata.createBindings( session.getFactory() );
this.resultSetMapping = ResultSetMapping.resolveResultSetMapping( sqlString, true, session.getFactory() );
this.resultSetMapping = resolveResultSetMapping( sqlString, true, session.getFactory() );
this.resultMappingSuppliedToCtor = false;
}
@ -351,7 +337,7 @@ public class NativeQueryImpl<R>
String registeredName,
boolean isDynamic,
SharedSessionContractImplementor session) {
return ResultSetMapping.resolveResultSetMapping( registeredName, isDynamic, session.getFactory() );
return resolveResultSetMapping( registeredName, isDynamic, session.getFactory() );
}
public List<ParameterOccurrence> getParameterOccurrences() {
@ -359,24 +345,19 @@ public class NativeQueryImpl<R>
}
private ParameterInterpretation resolveParameterInterpretation(
String sqlString,
SharedSessionContractImplementor session) {
final SessionFactoryImplementor sessionFactory = session.getFactory();
final QueryEngine queryEngine = sessionFactory.getQueryEngine();
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
String sqlString, SharedSessionContractImplementor session) {
return session.getFactory().getQueryEngine().getInterpretationCache()
.resolveNativeQueryParameters( sqlString,
s -> parameterInterpretation( sqlString, session ) );
}
return interpretationCache.resolveNativeQueryParameters(
sqlString,
s -> {
final ParameterRecognizerImpl parameterRecognizer = new ParameterRecognizerImpl();
session.getFactory().getServiceRegistry()
.requireService( NativeQueryInterpreter.class )
.recognizeParameters( sqlString, parameterRecognizer );
return new ParameterInterpretationImpl( parameterRecognizer );
}
);
private static ParameterInterpretationImpl parameterInterpretation(
String sqlString, SharedSessionContractImplementor session) {
final ParameterRecognizerImpl parameterRecognizer = new ParameterRecognizerImpl();
session.getFactory().getServiceRegistry()
.requireService( NativeQueryInterpreter.class )
.recognizeParameters( sqlString, parameterRecognizer );
return new ParameterInterpretationImpl( parameterRecognizer );
}
protected void applyOptions(NamedNativeQueryMemento<?> memento) {
@ -389,7 +370,7 @@ public class NativeQueryImpl<R>
setFirstResult( memento.getFirstResult() );
}
final Set<String> copy = CollectionHelper.makeCopy( memento.getQuerySpaces() );
final Set<String> copy = makeCopy( memento.getQuerySpaces() );
if ( copy != null ) {
this.querySpaces = copy;
}
@ -557,16 +538,14 @@ public class NativeQueryImpl<R>
public Boolean isSelectQuery() {
if ( resultMappingSuppliedToCtor
|| resultSetMapping.getNumberOfResultBuilders() > 0
|| isReadOnly() ) {
|| isReadOnly()
// as a last resort, see if the SQL starts with "select"
|| startsWithSelect() ) {
return true;
}
if ( startsWithSelect() ) {
// as a last resort, see if the SQL starts with "select"
return true;
else {
return null;
}
return null;
}
private boolean startsWithSelect() {
@ -605,21 +584,16 @@ public class NativeQueryImpl<R>
private boolean shouldFlush() {
if ( getSession().isTransactionInProgress() ) {
FlushMode effectiveFlushMode = getQueryOptions().getFlushMode();
if ( effectiveFlushMode == null ) {
effectiveFlushMode = getSession().getHibernateFlushMode();
}
if ( effectiveFlushMode == FlushMode.ALWAYS ) {
return true;
}
if ( effectiveFlushMode == FlushMode.AUTO ) {
return getSession().getFactory().getSessionFactoryOptions().isJpaBootstrap();
}
final FlushMode flushMode = getQueryOptions().getFlushMode();
return switch ( flushMode == null ? getSession().getHibernateFlushMode() : flushMode ) {
case AUTO -> getSession().getFactory().getSessionFactoryOptions().isJpaBootstrap();
case ALWAYS -> true;
default -> false;
};
}
else {
return false;
}
return false;
}
@Override
@ -644,19 +618,16 @@ public class NativeQueryImpl<R>
}
protected SelectQueryPlan<R> resolveSelectQueryPlan() {
if ( isCacheableQuery() ) {
final QueryInterpretationCache.Key cacheKey = generateSelectInterpretationsKey( resultSetMapping );
return getSession().getFactory().getQueryEngine().getInterpretationCache()
.resolveSelectQueryPlan( cacheKey, () -> createQueryPlan( resultSetMapping ) );
}
else {
return createQueryPlan( resultSetMapping );
}
return isCacheableQuery()
? getInterpretationCache()
.resolveSelectQueryPlan( selectInterpretationsKey(), this::createQueryPlan )
: createQueryPlan();
}
private NativeSelectQueryPlan<R> createQueryPlan(ResultSetMapping resultSetMapping) {
final String sqlString = expandParameterLists();
private NativeSelectQueryPlan<R> createQueryPlan() {
final NativeSelectQueryDefinition<R> queryDefinition = new NativeSelectQueryDefinition<>() {
final String sqlString = expandParameterLists();
@Override
public String getSqlString() {
return sqlString;
@ -682,18 +653,17 @@ public class NativeQueryImpl<R>
return querySpaces;
}
};
return getSessionFactory().getQueryEngine().getNativeQueryInterpreter()
.createQueryPlan( queryDefinition, getSessionFactory() );
return getNativeQueryInterpreter().createQueryPlan( queryDefinition, getSessionFactory() );
}
/*
* Used by Hibernate Reactive
*/
protected NativeSelectQueryPlan<Long> createCountQueryPlan() {
final BasicType<Long> longType = getSessionFactory().getTypeConfiguration().getBasicTypeForJavaType(Long.class);
final String sqlString = expandParameterLists();
final NativeSelectQueryDefinition<Long> queryDefinition = new NativeSelectQueryDefinition<>() {
final BasicType<Long> longType = getTypeConfiguration().getBasicTypeForJavaType(Long.class);
final String sqlString = expandParameterLists();
@Override
public String getSqlString() {
return "select count(*) from (" + sqlString + ") a_";
@ -721,9 +691,15 @@ public class NativeQueryImpl<R>
return querySpaces;
}
};
return getNativeQueryInterpreter().createQueryPlan( queryDefinition, getSessionFactory() );
}
return getSessionFactory().getQueryEngine().getNativeQueryInterpreter()
.createQueryPlan( queryDefinition, getSessionFactory() );
private TypeConfiguration getTypeConfiguration() {
return getSessionFactory().getTypeConfiguration();
}
private NativeQueryInterpreter getNativeQueryInterpreter() {
return getSessionFactory().getQueryEngine().getNativeQueryInterpreter();
}
protected String expandParameterLists() {
@ -749,8 +725,8 @@ public class NativeQueryImpl<R>
}
final Collection<?> bindValues = binding.getBindValues();
int bindValueCount = bindValues.size();
int bindValueMaxCount = determineBindValueMaxCount( paddingEnabled, inExprLimit, bindValueCount );
final int bindValueCount = bindValues.size();
final int bindValueMaxCount = determineBindValueMaxCount( paddingEnabled, inExprLimit, bindValueCount );
if ( inExprLimit > 0 && bindValueCount > inExprLimit ) {
log.tooManyInExpressions(
@ -773,7 +749,7 @@ public class NativeQueryImpl<R>
boolean isEnclosedInParens = true;
for ( int i = sourcePosition - 1; i >= 0; i-- ) {
final char ch = sqlString.charAt( i );
if ( !Character.isWhitespace( ch ) ) {
if ( !isWhitespace( ch ) ) {
isEnclosedInParens = ch == '(';
break;
}
@ -781,7 +757,7 @@ public class NativeQueryImpl<R>
if ( isEnclosedInParens ) {
for ( int i = sourcePosition + 1; i < sqlString.length(); i++ ) {
final char ch = sqlString.charAt( i );
if ( !Character.isWhitespace( ch ) ) {
if ( !isWhitespace( ch ) ) {
isEnclosedInParens = ch == ')';
break;
}
@ -802,16 +778,11 @@ public class NativeQueryImpl<R>
final String expansionListAsString;
// HHH-8901
if ( bindValueMaxCount == 0 ) {
if ( isEnclosedInParens ) {
expansionListAsString = "null";
}
else {
expansionListAsString = "(null)";
}
expansionListAsString = isEnclosedInParens ? "null" : "(null)";
}
else {
// Shift 1 bit instead of multiplication by 2
char[] chars;
final char[] chars;
if ( isEnclosedInParens ) {
chars = new char[( bindValueMaxCount << 1 ) - 1];
chars[0] = '?';
@ -863,7 +834,7 @@ public class NativeQueryImpl<R>
return bindValueMaxCount;
}
private SelectInterpretationsKey generateSelectInterpretationsKey(JdbcValuesMappingProducer resultSetMapping) {
private SelectInterpretationsKey selectInterpretationsKey() {
return new SelectInterpretationsKey(
getQueryString(),
resultSetMapping,
@ -894,26 +865,33 @@ public class NativeQueryImpl<R>
return resolveNonSelectQueryPlan().executeUpdate( this );
}
private BasicTypeRegistry getBasicTypeRegistry() {
return getTypeConfiguration().getBasicTypeRegistry();
}
private QueryInterpretationCache getInterpretationCache() {
return getSession().getFactory().getQueryEngine().getInterpretationCache();
}
private NonSelectQueryPlan resolveNonSelectQueryPlan() {
NonSelectQueryPlan queryPlan = null;
final QueryInterpretationCache.Key cacheKey = generateNonSelectInterpretationsKey();
if ( cacheKey != null ) {
queryPlan = getSession().getFactory().getQueryEngine().getInterpretationCache().getNonSelectQueryPlan( cacheKey );
queryPlan = getInterpretationCache().getNonSelectQueryPlan( cacheKey );
}
if ( queryPlan == null ) {
final String sqlString = expandParameterLists();
queryPlan = new NativeNonSelectQueryPlanImpl( sqlString, querySpaces, parameterOccurrences );
if ( cacheKey != null ) {
getSession().getFactory().getQueryEngine().getInterpretationCache().cacheNonSelectQueryPlan( cacheKey, queryPlan );
getInterpretationCache().cacheNonSelectQueryPlan( cacheKey, queryPlan );
}
}
return queryPlan;
}
protected NonSelectInterpretationsKey generateNonSelectInterpretationsKey() {
// todo (6.0) - should this account for query spaces in determining "cacheable"?
return isCacheableQuery()
@ -933,12 +911,7 @@ public class NativeQueryImpl<R>
}
public NativeQueryImplementor<R> addScalar(int position, Class<?> type) {
return registerBuilder(
Builders.scalar(
position,
getSessionFactory().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( type )
)
);
return registerBuilder( Builders.scalar( position, getBasicTypeRegistry().getRegisteredType( type ) ) );
}
protected NativeQueryImplementor<R> registerBuilder(ResultBuilder builder) {
@ -948,13 +921,8 @@ public class NativeQueryImpl<R>
@Override
public NativeQuery<R> addScalar(String columnAlias, @SuppressWarnings("rawtypes") BasicTypeReference type) {
return registerBuilder(
Builders.scalar(
columnAlias,
getSessionFactory().getTypeConfiguration().getBasicTypeRegistry()
.resolve( (BasicTypeReference<?>) type )
)
);
return registerBuilder( Builders.scalar( columnAlias,
getBasicTypeRegistry().resolve( (BasicTypeReference<?>) type ) ) );
}
@Override
@ -1003,10 +971,8 @@ public class NativeQueryImpl<R>
@Override
public <J> InstantiationResultNode<J> addInstantiation(Class<J> targetJavaType) {
final DynamicResultBuilderInstantiation<J> builder = Builders.instantiation(
targetJavaType,
getSessionFactory()
);
final DynamicResultBuilderInstantiation<J> builder =
Builders.instantiation( targetJavaType, getSessionFactory() );
registerBuilder( builder );
return builder;
}
@ -1038,11 +1004,8 @@ public class NativeQueryImpl<R>
@Override
public DynamicResultBuilderEntityStandard addRoot(String tableAlias, String entityName) {
final DynamicResultBuilderEntityStandard resultBuilder = Builders.entity(
tableAlias,
entityName,
getSessionFactory()
);
final DynamicResultBuilderEntityStandard resultBuilder =
Builders.entity( tableAlias, entityName, getSessionFactory() );
resultSetMapping.addResultBuilder( resultBuilder );
return resultBuilder;
}
@ -1054,7 +1017,7 @@ public class NativeQueryImpl<R>
@Override
public NativeQueryImplementor<R> addEntity(String entityName) {
return addEntity( StringHelper.unqualify( entityName ), entityName );
return addEntity( unqualify( entityName ), entityName );
}
@Override
@ -1076,7 +1039,7 @@ public class NativeQueryImpl<R>
@Override
public NativeQueryImplementor<R> addEntity(Class<R> entityType, LockMode lockMode) {
return addEntity( StringHelper.unqualify( entityType.getName() ), entityType.getName(), lockMode);
return addEntity( unqualify( entityType.getName() ), entityType.getName(), lockMode);
}
@Override
@ -1103,7 +1066,7 @@ public class NativeQueryImpl<R>
}
private FetchReturn createFetchJoin(String tableAlias, String path) {
int loc = path.indexOf( '.' );
final int loc = path.indexOf( '.' );
if ( loc < 0 ) {
throw new PathException( "Not a property path '" + path + "'" );
}
@ -1141,7 +1104,7 @@ public class NativeQueryImpl<R>
if ( querySpaces == null ) {
querySpaces = new HashSet<>();
}
Collections.addAll( querySpaces, spaces );
addAll( querySpaces, spaces );
}
}
@ -1150,25 +1113,23 @@ public class NativeQueryImpl<R>
if ( querySpaces == null ) {
querySpaces = new HashSet<>();
}
Collections.addAll( querySpaces, (String[]) spaces );
addAll( querySpaces, (String[]) spaces );
}
}
private MappingMetamodelImplementor getMappingMetamodel() {
return getSession().getFactory().getRuntimeMetamodels().getMappingMetamodel();
}
@Override
public NativeQueryImplementor<R> addSynchronizedEntityName(String entityName) throws MappingException {
final EntityPersister entityDescriptor = getSession().getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entityName );
addQuerySpaces( entityDescriptor.getQuerySpaces() );
public NativeQueryImplementor<R> addSynchronizedEntityName(String entityName) {
addQuerySpaces( getMappingMetamodel().getEntityDescriptor( entityName ).getQuerySpaces() );
return this;
}
@Override
public NativeQueryImplementor<R> addSynchronizedEntityClass(@SuppressWarnings("rawtypes") Class entityClass) throws MappingException {
final EntityPersister entityDescriptor = getSession().getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entityClass );
addQuerySpaces( entityDescriptor.getQuerySpaces() );
public NativeQueryImplementor<R> addSynchronizedEntityClass(@SuppressWarnings("rawtypes") Class entityClass) {
addQuerySpaces( getMappingMetamodel().getEntityDescriptor( entityClass ).getQuerySpaces() );
return this;
}
@ -1303,19 +1264,19 @@ public class NativeQueryImpl<R>
}
protected void applySynchronizeSpace(Object value) {
if ( value instanceof String ) {
addSynchronizedQuerySpace( (String) value );
if ( value instanceof String string ) {
addSynchronizedQuerySpace( string );
}
else if ( value instanceof Class ) {
addSynchronizedEntityClass( (Class<?>) value );
else if ( value instanceof Class<?> clazz ) {
addSynchronizedEntityClass( clazz );
}
else if ( value instanceof Object[] ) {
for ( Object element : (Object[]) value ) {
else if ( value instanceof Object[] array ) {
for ( Object element : array ) {
applySynchronizeSpace( element );
}
}
else if ( value instanceof Iterable ) {
for ( Object element : (Iterable<?>) value ) {
else if ( value instanceof Iterable<?> iterable ) {
for ( Object element : iterable ) {
applySynchronizeSpace( element );
}
}
@ -1474,9 +1435,6 @@ public class NativeQueryImpl<R>
return this;
}
@Override
public NativeQueryImplementor<R> setParameterList(int position, @SuppressWarnings("rawtypes") Collection values) {
super.setParameterList( position, values );
@ -1620,12 +1578,9 @@ public class NativeQueryImpl<R>
@Override
public ParameterMetadataImplementor toParameterMetadata(SharedSessionContractImplementor session1) {
if ( CollectionHelper.isEmpty( positionalParameters ) && CollectionHelper.isEmpty( namedParameters ) ) {
return ParameterMetadataImpl.EMPTY;
}
else {
return new ParameterMetadataImpl( positionalParameters, namedParameters );
}
return isEmpty( positionalParameters ) && isEmpty( namedParameters )
? ParameterMetadataImpl.EMPTY
: new ParameterMetadataImpl( positionalParameters, namedParameters );
}
@Override
@ -1635,17 +1590,17 @@ public class NativeQueryImpl<R>
@Override
public String toString() {
final StringBuilder buffer = new StringBuilder( "ParameterInterpretationImpl (" )
.append( sqlString )
.append( ") : {" );
final StringBuilder buffer =
new StringBuilder( "ParameterInterpretationImpl (" )
.append( sqlString )
.append( ") : {" );
final String lineSeparator = System.lineSeparator();
if ( CollectionHelper.isNotEmpty( parameterList ) ) {
if ( isNotEmpty( parameterList ) ) {
for ( int i = 0, size = parameterList.size(); i < size; i++ ) {
buffer.append( lineSeparator ).append( " ," );
}
buffer.setLength( buffer.length() - 1 );
}
return buffer.append( lineSeparator ).append( "}" ).toString();
}
}

View File

@ -113,8 +113,8 @@ abstract class AbstractSqmSelectionQuery<R> extends AbstractSelectionQuery<R> {
private SqmSelectStatement<R> getSqmSelectStatement() {
final SqmStatement<R> sqmStatement = getSqmStatement();
if ( sqmStatement instanceof SqmSelectStatement ) {
return (SqmSelectStatement<R>) sqmStatement;
if ( sqmStatement instanceof SqmSelectStatement<R> selectStatement ) {
return selectStatement;
}
else {
throw new IllegalSelectQueryException( "Not a select query" );
@ -157,8 +157,9 @@ abstract class AbstractSqmSelectionQuery<R> extends AbstractSelectionQuery<R> {
if ( keyedPage == null ) {
throw new IllegalArgumentException( "KeyedPage was null" );
}
final List<KeyedResult<R>> results = new SqmSelectionQueryImpl<KeyedResult<R>>( this, keyedPage )
.getResultList();
final List<KeyedResult<R>> results =
new SqmSelectionQueryImpl<KeyedResult<R>>( this, keyedPage )
.getResultList();
final Page page = keyedPage.getPage();
return new KeyedResultList<>(
collectResults( results, page.getSize(), keyedPage.getKeyInterpretation() ),

View File

@ -19,7 +19,6 @@ import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.engine.jdbc.dialect.internal.DialectResolverInitiator;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolver;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.boot.spi.Bootstrap;
import org.hibernate.orm.test.dialect.resolver.TestingDialectResolutionInfo;
@ -34,6 +33,8 @@ import org.junit.jupiter.api.Test;
import jakarta.persistence.SharedCacheMode;
import jakarta.persistence.ValidationMode;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
@ -294,6 +295,22 @@ public class ConfigurationObjectSettingTest {
// verifySchemaGenSettingsPrecedence();
}
public static Map<String,String> toMap(String... pairs) {
assert pairs.length % 2 == 0;
switch ( pairs.length ) {
case 0:
return emptyMap();
case 2:
return singletonMap( pairs[0], pairs[1] );
default:
final Map<String,String> result = new HashMap<>();
for ( int i = 0; i < pairs.length; i+=2 ) {
result.put( pairs[i], pairs[i+1] );
}
return result;
}
}
private void verifySchemaGenSettings(
String dbActionSettingName,
String scriptActionSettingName,
@ -304,7 +321,7 @@ public class ConfigurationObjectSettingTest {
final boolean createSchemas = true;
final String dbName = "H2";
final Map<String, String> settings = CollectionHelper.toMap(
final Map<String, String> settings = toMap(
dbActionSettingName, dbAction.getExternalJpaName(),
scriptActionSettingName, scriptAction.getExternalJpaName(),
createSchemasSettingName, Boolean.toString( createSchemas ),

View File

@ -7,7 +7,6 @@ package org.hibernate.orm.test.mapping.mutability.attribute;
import java.util.Map;
import org.hibernate.annotations.Mutability;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.Property;
import org.hibernate.metamodel.mapping.AttributeMapping;
@ -154,7 +153,7 @@ public class ImmutabilityMapAsBasicTests {
scope.inTransaction( (session) -> {
session.persist( new TestEntity(
1,
CollectionHelper.toMap(
Map.of(
"abc", "123",
"def", "456"
)

View File

@ -7,7 +7,6 @@ package org.hibernate.orm.test.mapping.mutability.attribute;
import java.util.Map;
import org.hibernate.annotations.Immutable;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
@ -171,7 +170,7 @@ public class ImmutableMapAsBasicTests {
scope.inTransaction( (session) -> {
session.persist( new TestEntity(
1,
CollectionHelper.toMap(
Map.of(
"abc", "123",
"def", "456"
)

View File

@ -6,7 +6,6 @@ package org.hibernate.orm.test.mapping.mutability.attribute;
import java.util.Map;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.orm.test.mapping.mutability.converted.MapConverter;
import org.hibernate.testing.jdbc.SQLStatementInspector;
@ -86,7 +85,7 @@ public class MutableMapAsBasicTests {
scope.inTransaction( (session) -> {
session.persist( new TestEntity(
1,
CollectionHelper.toMap(
Map.of(
"abc", "123",
"def", "456"
)

View File

@ -4,12 +4,15 @@
*/
package org.hibernate.orm.test.mapping.mutability.converted;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.internal.util.collections.CollectionHelper;
import jakarta.persistence.AttributeConverter;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static org.hibernate.internal.util.StringHelper.isEmpty;
import static org.hibernate.internal.util.StringHelper.join;
import static org.hibernate.internal.util.StringHelper.split;
@ -20,11 +23,37 @@ import static org.hibernate.internal.util.StringHelper.split;
public class MapConverter implements AttributeConverter<Map<String, String>, String> {
@Override
public String convertToDatabaseColumn(Map<String, String> map) {
return CollectionHelper.isEmpty( map ) ? null : join( ", ", CollectionHelper.asPairs( map ) );
return CollectionHelper.isEmpty( map ) ? null : join( ", ", asPairs( map ) );
}
@Override
public Map<String, String> convertToEntityAttribute(String pairs) {
return isEmpty( pairs ) ? null : CollectionHelper.toMap( split( ", ", pairs ) );
return isEmpty( pairs ) ? null : toMap( split( ", ", pairs ) );
}
public static Map<String,String> toMap(String... pairs) {
assert pairs.length % 2 == 0;
switch ( pairs.length ) {
case 0:
return emptyMap();
case 2:
return singletonMap( pairs[0], pairs[1] );
default:
final Map<String,String> result = new HashMap<>();
for ( int i = 0; i < pairs.length; i+=2 ) {
result.put( pairs[i], pairs[i+1] );
}
return result;
}
}
public static String[] asPairs(Map<String,String> map) {
final String[] pairs = new String[ map.size() * 2 ];
int i = 0;
for ( Map.Entry<String,String> entry : map.entrySet() ) {
pairs[i++] = entry.getKey();
pairs[i++] = entry.getValue();
}
return pairs;
}
}