You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2026/06/08 00:19:36 UTC
(cayenne) 01/07: QueryMetadata cleanup
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 <an...@objectstyle.com>
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(