This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch past-M2 in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit 8dc259abcf5812ad0ee589e697568814e8769593 Author: Andrus Adamchik <[email protected]> AuthorDate: Sun Jun 7 11:31:21 2026 -0400 QueryMetadata cleanup * QueryMetadataWrapper is entirely unneeded --- .../cayenne/access/DataDomainQueryAction.java | 53 ++++----- .../java/org/apache/cayenne/query/QueryChain.java | 9 +- .../apache/cayenne/query/QueryMetadataWrapper.java | 128 --------------------- .../org/apache/cayenne/query/RefreshQuery.java | 21 ++-- 4 files changed, 41 insertions(+), 170 deletions(-) diff --git a/cayenne/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java b/cayenne/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java index 6858c3f63..ed842df51 100644 --- a/cayenne/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java +++ b/cayenne/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java @@ -77,7 +77,7 @@ import java.util.function.Function; * Performs query routing and execution. During execution phase intercepts * callbacks to the OperationObserver, remapping results to the original * pre-routed queries. - * + * * @since 1.2 */ class DataDomainQueryAction implements QueryRouter, OperationObserver { @@ -452,11 +452,11 @@ class DataDomainQueryAction implements QueryRouter, OperationObserver { // response may already be initialized by the factory above ... // it is null if there was a preexisting cache entry cacheHit = (response == null); - + if (response == null || wasResponseNull) { response = new ListResponse(cachedResults); } - + // Mark as cached result - lists need copying whether hit or miss cachedResult = true; @@ -545,12 +545,12 @@ class DataDomainQueryAction implements QueryRouter, OperationObserver { ObjectConversionStrategy<?, ?> converter = getConverter(); // local copy because it can change while iterating QueryResponse response = this.response; - for (response.reset(); response.next();) { + for (response.reset(); response.next(); ) { if (response.isList()) { List<?> mainRows = response.currentList(); // List<DataRow> or List<Object[]> if (mainRows != null && !mainRows.isEmpty()) { List<?> result = converter.convert((List) mainRows); - if(result != mainRows) { + if (result != mainRows) { updateResponse(mainRows, result); } } @@ -735,15 +735,14 @@ class DataDomainQueryAction implements QueryRouter, OperationObserver { .synchronizedRootResultNodeFromDataRows(normalizedRows); } else { // When results come from cache (not a refresh operation), wrap metadata to prevent refreshing objects - QueryMetadata effectiveMetadata = shouldSkipRefresh() && metadata.isRefreshingObjects() - ? new NonRefreshingQueryMetadataWrapper(metadata) + QueryMetadata effectiveMetadata = shouldSkipRefresh() && metadata.isRefreshingObjects() + ? nonRefreshingMetadata(metadata) : metadata; - HierarchicalObjectResolver resolver = new HierarchicalObjectResolver(context, effectiveMetadata); - return resolver + return new HierarchicalObjectResolver(context, effectiveMetadata) .synchronizedRootResultNodeFromDataRows(prefetchTree, normalizedRows, prefetchResultsByPath); } } - + private boolean shouldSkipRefresh() { // Skip refresh only for cache hits to prevent stale cached data from clobbering newer in-memory state // For cache misses (including explicit refresh operations), cacheHit is false, so refresh happens normally @@ -766,6 +765,15 @@ class DataDomainQueryAction implements QueryRouter, OperationObserver { } } + private QueryMetadata nonRefreshingMetadata(QueryMetadata metadata) { + return new QueryMetadataProxy(metadata) { + @Override + public boolean isRefreshingObjects() { + return false; + } + }; + } + class SingleObjectConversionStrategy extends ObjectConversionStrategy<DataRow, Persistent> { @Override @@ -865,7 +873,7 @@ class DataDomainQueryAction implements QueryRouter, OperationObserver { List<Object[]> result = createResultList(mainRows, needConversion); // no conversions needed for scalar positions; - if(needConversion) { + if (needConversion) { // reuse Object[]'s to fill them with resolved objects List<PrefetchProcessorNode> segmentNodes = doInPlaceConversion(result); @@ -895,19 +903,19 @@ class DataDomainQueryAction implements QueryRouter, OperationObserver { } private List<Object[]> createResultList(List<Object[]> mainRows, boolean needConversion) { - if(!cachedResult) { + if (!cachedResult) { // fast-path, we can reuse existing rows return mainRows; } - if(!needConversion) { + if (!needConversion) { // no conversion needed, so can clone only top-level list return new ArrayList<>(mainRows); } // slowest path, deep copy everything List<Object[]> result = new ArrayList<>(mainRows.size()); - for(Object[] row : mainRows) { + for (Object[] row : mainRows) { result.add(Arrays.copyOf(row, metadata.getResultSetMapping().size())); } return result; @@ -949,7 +957,7 @@ class DataDomainQueryAction implements QueryRouter, OperationObserver { private List<PrefetchProcessorNode> doInPlaceConversion(List<Object[]> result) { List<Object> resultSetMapping = metadata.getResultSetMapping(); int width = resultSetMapping.size(); - int height = result.size(); + int height = result.size(); List<PrefetchProcessorNode> segmentNodes = new ArrayList<>(width); for (int i = 0; i < width; i++) { Object mapping = resultSetMapping.get(i); @@ -1035,19 +1043,4 @@ class DataDomainQueryAction implements QueryRouter, OperationObserver { return mapper.apply(parentStrategy.convert(object)); } } - - /** - * Wrapper that overrides isRefreshingObjects() to return false, preventing cached - * query results from clobbering newer in-memory object state. - */ - static class NonRefreshingQueryMetadataWrapper extends QueryMetadataProxy { - NonRefreshingQueryMetadataWrapper(QueryMetadata delegate) { - super(delegate); - } - - @Override - public boolean isRefreshingObjects() { - return false; - } - } } diff --git a/cayenne/src/main/java/org/apache/cayenne/query/QueryChain.java b/cayenne/src/main/java/org/apache/cayenne/query/QueryChain.java index 37fd17dc5..d2419d045 100644 --- a/cayenne/src/main/java/org/apache/cayenne/query/QueryChain.java +++ b/cayenne/src/main/java/org/apache/cayenne/query/QueryChain.java @@ -110,8 +110,11 @@ public class QueryChain implements Query { * Returns default metadata. */ public QueryMetadata getMetaData(EntityResolver resolver) { - QueryMetadataWrapper wrapper = new QueryMetadataWrapper(DefaultQueryMetadata.defaultMetadata); - wrapper.override(QueryMetadata.FETCHING_DATA_ROWS_PROPERTY, Boolean.TRUE); - return wrapper; + return new QueryMetadataProxy(DefaultQueryMetadata.defaultMetadata) { + @Override + public boolean isFetchingDataRows() { + return true; + } + }; } } diff --git a/cayenne/src/main/java/org/apache/cayenne/query/QueryMetadataWrapper.java b/cayenne/src/main/java/org/apache/cayenne/query/QueryMetadataWrapper.java deleted file mode 100644 index fd255e258..000000000 --- a/cayenne/src/main/java/org/apache/cayenne/query/QueryMetadataWrapper.java +++ /dev/null @@ -1,128 +0,0 @@ -/***************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.cayenne.query; - -import java.util.HashMap; -import java.util.Map; - -/** - * A wrapper for a QueryMetadata instance allowing that may override a subset of metadata - * properties. - * - * @since 1.2 - */ -class QueryMetadataWrapper extends QueryMetadataProxy { - - static final String CACHE_KEY_PROPERTY = "QueryMetadataWrapper.CacheKey"; - - Map<String, Object> overrides; - - public QueryMetadataWrapper(QueryMetadata info) { - super(info); - } - - /** - * Overrides a property with an alternative value. Property names are defined in the - * {@link QueryMetadata} interface. - */ - void override(String key, Object value) { - if (overrides == null) { - overrides = new HashMap<>(); - } - - overrides.put(key, value); - } - - boolean overrideExists(String key) { - return overrides != null && overrides.containsKey(key); - } - - public String getCacheKey() { - return (overrideExists(CACHE_KEY_PROPERTY)) - ? (String) overrides.get(CACHE_KEY_PROPERTY) - : super.getCacheKey(); - } - - /** - * @since 3.0 - */ - public QueryCacheStrategy getCacheStrategy() { - return (overrideExists(QueryMetadata.CACHE_STRATEGY_PROPERTY)) - ? (QueryCacheStrategy) overrides.get(QueryMetadata.CACHE_STRATEGY_PROPERTY) - : super.getCacheStrategy(); - } - - /** - * @since 4.0 - */ - public String getCacheGroup() { - if(overrideExists(QueryMetadata.CACHE_GROUPS_PROPERTY)) { - String[] cacheGroups = (String[]) overrides.get(QueryMetadata.CACHE_GROUPS_PROPERTY); - if(cacheGroups == null || cacheGroups.length == 0) { - return null; - } else { - return cacheGroups[0]; - } - } - - return super.getCacheGroup(); - } - - public boolean isFetchingDataRows() { - if (!overrideExists(QueryMetadata.FETCHING_DATA_ROWS_PROPERTY)) { - return super.isFetchingDataRows(); - } - - Boolean b = (Boolean) overrides.get(QueryMetadata.FETCHING_DATA_ROWS_PROPERTY); - return b != null && b; - } - - public boolean isRefreshingObjects() { - return true; - } - - public int getPageSize() { - if (!overrideExists(QueryMetadata.PAGE_SIZE_PROPERTY)) { - return super.getPageSize(); - } - - Number n = (Number) overrides.get(QueryMetadata.PAGE_SIZE_PROPERTY); - return n != null ? n.intValue() : 0; - } - - public int getFetchLimit() { - if (!overrideExists(QueryMetadata.FETCH_LIMIT_PROPERTY)) { - return super.getFetchLimit(); - } - - Number n = (Number) overrides.get(QueryMetadata.FETCH_LIMIT_PROPERTY); - return n != null ? n.intValue() : 0; - } - - public int getStatementFetchSize() { - if (!overrideExists(QueryMetadata.STATEMENT_FETCH_SIZE_PROPERTY)) { - return super.getPageSize(); - } - - Number n = (Number) overrides.get(QueryMetadata.STATEMENT_FETCH_SIZE_PROPERTY); - return n != null ? n.intValue() : 0; - } - -} diff --git a/cayenne/src/main/java/org/apache/cayenne/query/RefreshQuery.java b/cayenne/src/main/java/org/apache/cayenne/query/RefreshQuery.java index e0227056e..43a9ca0ab 100644 --- a/cayenne/src/main/java/org/apache/cayenne/query/RefreshQuery.java +++ b/cayenne/src/main/java/org/apache/cayenne/query/RefreshQuery.java @@ -122,15 +122,18 @@ public class RefreshQuery implements Query { public QueryMetadata getMetaData(EntityResolver resolver) { QueryMetadata md = query.getMetaData(resolver); - - QueryMetadataWrapper wrappedMd = new QueryMetadataWrapper(md); - if (QueryCacheStrategy.LOCAL_CACHE == md.getCacheStrategy()) { - wrappedMd.override(QueryMetadata.CACHE_STRATEGY_PROPERTY, QueryCacheStrategy.LOCAL_CACHE_REFRESH); - } else if (QueryCacheStrategy.SHARED_CACHE == md.getCacheStrategy()) { - wrappedMd.override(QueryMetadata.CACHE_STRATEGY_PROPERTY, QueryCacheStrategy.SHARED_CACHE_REFRESH); - } - - return wrappedMd; + QueryCacheStrategy refreshStrategy = switch (md.getCacheStrategy()) { + case LOCAL_CACHE -> QueryCacheStrategy.LOCAL_CACHE_REFRESH; + case SHARED_CACHE -> QueryCacheStrategy.SHARED_CACHE_REFRESH; + case null, default -> md.getCacheStrategy(); + }; + + return new QueryMetadataProxy(md) { + @Override + public QueryCacheStrategy getCacheStrategy() { + return refreshStrategy; + } + }; } public void route(
