PartTreeQueryCache.java
/*
* Copyright 2024-2025 the original author or authors.
*
* 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
*
* https://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.
*/
package org.springframework.data.jpa.repository.query;
import java.util.BitSet;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import org.springframework.data.domain.Sort;
import org.jspecify.annotations.Nullable;
import org.springframework.util.ObjectUtils;
/**
* Cache for PartTree queries.
*
* @author Christoph Strobl
*/
class PartTreeQueryCache {
private final Map<CacheKey, JpqlQueryCreator> cache = Collections.synchronizedMap(new LinkedHashMap<>() {
@Override
protected boolean removeEldestEntry(Map.Entry<CacheKey, JpqlQueryCreator> eldest) {
return size() > 256;
}
});
@Nullable
JpqlQueryCreator get(Sort sort, JpaParametersParameterAccessor accessor) {
return cache.get(CacheKey.of(sort, accessor));
}
@Nullable
JpqlQueryCreator put(Sort sort, JpaParametersParameterAccessor accessor, JpqlQueryCreator creator) {
return cache.put(CacheKey.of(sort, accessor), creator);
}
static class CacheKey {
private final Sort sort;
/**
* Bitset of null/non-null parameter values. A 0 bit means the parameter value is {@code null}, a 1 bit means the
* parameter is not {@code null}.
*/
private final BitSet params;
public CacheKey(Sort sort, BitSet params) {
this.sort = sort;
this.params = params;
}
static CacheKey of(Sort sort, JpaParametersParameterAccessor accessor) {
Object[] values = accessor.getValues();
if (ObjectUtils.isEmpty(values)) {
return new CacheKey(sort, new BitSet());
}
return new CacheKey(sort, toNullableMap(values));
}
static BitSet toNullableMap(Object[] args) {
BitSet bitSet = new BitSet(args.length);
for (int i = 0; i < args.length; i++) {
bitSet.set(i, args[i] != null);
}
return bitSet;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CacheKey cacheKey = (CacheKey) o;
return sort.equals(cacheKey.sort) && params.equals(cacheKey.params);
}
@Override
public int hashCode() {
return Objects.hash(sort, params);
}
}
}