mirror of https://github.com/apache/openjpa.git
OPENJPA-900: Reduce reflection in hint processing. Redesign with explicit hint keys.
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@899529 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
dad4ad1952
commit
b5a412fd42
|
@ -18,14 +18,18 @@
|
|||
*/
|
||||
package org.apache.openjpa.jdbc.conf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.openjpa.conf.BrokerFactoryValue;
|
||||
import org.apache.openjpa.conf.OpenJPAProductDerivation;
|
||||
import org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory;
|
||||
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
|
||||
import org.apache.openjpa.jdbc.sql.MySQLDictionary;
|
||||
import org.apache.openjpa.jdbc.sql.OracleDictionary;
|
||||
import org.apache.openjpa.lib.conf.AbstractProductDerivation;
|
||||
|
@ -37,13 +41,7 @@ import org.apache.openjpa.lib.conf.ConfigurationProvider;
|
|||
public class JDBCProductDerivation extends AbstractProductDerivation
|
||||
implements OpenJPAProductDerivation {
|
||||
|
||||
private static Set<String> supportedQueryHints = new HashSet<String>(2);
|
||||
|
||||
static {
|
||||
supportedQueryHints.add(MySQLDictionary.SELECT_HINT);
|
||||
supportedQueryHints.add(OracleDictionary.SELECT_HINT);
|
||||
supportedQueryHints = Collections.unmodifiableSet(supportedQueryHints);
|
||||
}
|
||||
public static final String PREFIX = "openjpa.jdbc";
|
||||
|
||||
public void putBrokerFactoryAliases(Map m) {
|
||||
m.put("jdbc", JDBCBrokerFactory.class.getName());
|
||||
|
@ -62,8 +60,28 @@ public class JDBCProductDerivation extends AbstractProductDerivation
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hint keys correspond to some (not all) bean-style mutable property name in JDBCFetchConfiguration.
|
||||
* The fully qualified key is prefixed with <code>openjpa.jdbc</code>.
|
||||
*/
|
||||
private static Set<String> _hints = new HashSet<String>();
|
||||
static {
|
||||
_hints.add(PREFIX + ".EagerFetchMode");
|
||||
_hints.add(PREFIX + ".FetchDirection");
|
||||
_hints.add(PREFIX + ".TransactionIsolation");
|
||||
_hints.add(PREFIX + ".JoinSyntax");
|
||||
_hints.add(PREFIX + ".LRSSize");
|
||||
_hints.add(PREFIX + ".ResultSetType");
|
||||
_hints.add(PREFIX + ".SubclassFetchMode");
|
||||
|
||||
_hints.add(MySQLDictionary.SELECT_HINT);
|
||||
_hints.add(OracleDictionary.SELECT_HINT);
|
||||
|
||||
_hints = Collections.unmodifiableSet(_hints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedQueryHints() {
|
||||
return supportedQueryHints;
|
||||
return _hints;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -484,9 +484,17 @@ public class DelegatingFetchConfiguration
|
|||
}
|
||||
}
|
||||
|
||||
public void setHint(String name, Object value, boolean validate) {
|
||||
public void setHint(String name, Object value, Object original) {
|
||||
try {
|
||||
_fetch.setHint(name, value, validate);
|
||||
_fetch.setHint(name, value, original);
|
||||
} catch (RuntimeException re) {
|
||||
throw translate(re);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isHintSet(String key) {
|
||||
try {
|
||||
return _fetch.isHintSet(key);
|
||||
} catch (RuntimeException re) {
|
||||
throw translate(re);
|
||||
}
|
||||
|
@ -500,14 +508,6 @@ public class DelegatingFetchConfiguration
|
|||
}
|
||||
}
|
||||
|
||||
public void addHint(String name, Object value) {
|
||||
try {
|
||||
_fetch.addHint(name, value);
|
||||
} catch (RuntimeException re) {
|
||||
throw translate(re);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> getHints() {
|
||||
try {
|
||||
return _fetch.getHints();
|
||||
|
|
|
@ -126,7 +126,8 @@ public class QueryImpl
|
|||
|
||||
// remember the list of all the results we have returned so we
|
||||
// can free their resources when close or closeAll is called
|
||||
private transient final Collection<ResultList<?>> _resultLists = new ReferenceHashSet(ReferenceHashSet.WEAK);
|
||||
private transient final Collection<RemoveOnCloseResultList> _resultLists =
|
||||
new ReferenceHashSet(ReferenceHashSet.WEAK);
|
||||
|
||||
/**
|
||||
* Construct a query managed by the given broker.
|
||||
|
@ -1239,7 +1240,7 @@ public class QueryImpl
|
|||
boolean detach = (_broker.getAutoDetach() &
|
||||
AutoDetach.DETACH_NONTXREAD) > 0 && !_broker.isActive();
|
||||
boolean lrs = range.lrs && !ex.isAggregate(q) && !ex.hasGrouping(q);
|
||||
ResultList res = (!detach && lrs) ? _fc.newResultList(rop)
|
||||
ResultList<?> res = (!detach && lrs) ? _fc.newResultList(rop)
|
||||
: new EagerResultList(rop);
|
||||
res.setUserObject(new Object[]{rop,ex});
|
||||
_resultLists.add(decorateResultList(res));
|
||||
|
@ -1249,7 +1250,7 @@ public class QueryImpl
|
|||
/**
|
||||
* Optionally decorate the native result.
|
||||
*/
|
||||
protected ResultList decorateResultList(ResultList res) {
|
||||
protected RemoveOnCloseResultList decorateResultList(ResultList<?> res) {
|
||||
return new RemoveOnCloseResultList(res);
|
||||
}
|
||||
|
||||
|
@ -1260,7 +1261,7 @@ public class QueryImpl
|
|||
if (_packer != null)
|
||||
return _packer;
|
||||
|
||||
Class resultClass = (_resultClass != null) ? _resultClass
|
||||
Class<?> resultClass = (_resultClass != null) ? _resultClass
|
||||
: ex.getResultClass(q);
|
||||
if (resultClass == null)
|
||||
return null;
|
||||
|
@ -1279,7 +1280,7 @@ public class QueryImpl
|
|||
// into some result class
|
||||
_packer = new ResultPacker(_class, getAlias(), resultClass);
|
||||
} else if (resultClass != null) { // projection
|
||||
Class[] types = ex.getProjectionTypes(q);
|
||||
Class<?>[] types = ex.getProjectionTypes(q);
|
||||
_packer = new ResultPacker(types, aliases, resultClass);
|
||||
}
|
||||
}
|
||||
|
@ -1346,9 +1347,9 @@ public class QueryImpl
|
|||
|
||||
public static boolean isAccessPathDirty(Broker broker,
|
||||
ClassMetaData[] accessMetas) {
|
||||
Collection persisted = broker.getPersistedTypes();
|
||||
Collection updated = broker.getUpdatedTypes();
|
||||
Collection deleted = broker.getDeletedTypes();
|
||||
Collection<Class<?>> persisted = broker.getPersistedTypes();
|
||||
Collection<Class<?>> updated = broker.getUpdatedTypes();
|
||||
Collection<Class<?>> deleted = broker.getDeletedTypes();
|
||||
if (persisted.isEmpty() && updated.isEmpty() && deleted.isEmpty())
|
||||
return false;
|
||||
|
||||
|
@ -1358,7 +1359,7 @@ public class QueryImpl
|
|||
return true;
|
||||
|
||||
// compare dirty classes to the access path classes
|
||||
Class accClass;
|
||||
Class<?> accClass;
|
||||
for (int i = 0; i < accessMetas.length; i++) {
|
||||
if (accessMetas[i] == null)
|
||||
continue;
|
||||
|
@ -1369,14 +1370,14 @@ public class QueryImpl
|
|||
return true;
|
||||
|
||||
// check for dirty subclass
|
||||
for (Iterator dirty = persisted.iterator(); dirty.hasNext();)
|
||||
if (accClass.isAssignableFrom((Class) dirty.next()))
|
||||
for (Iterator<Class<?>> dirty = persisted.iterator(); dirty.hasNext();)
|
||||
if (accClass.isAssignableFrom(dirty.next()))
|
||||
return true;
|
||||
for (Iterator dirty = updated.iterator(); dirty.hasNext();)
|
||||
if (accClass.isAssignableFrom((Class) dirty.next()))
|
||||
for (Iterator<Class<?>> dirty = updated.iterator(); dirty.hasNext();)
|
||||
if (accClass.isAssignableFrom(dirty.next()))
|
||||
return true;
|
||||
for (Iterator dirty = deleted.iterator(); dirty.hasNext();)
|
||||
if (accClass.isAssignableFrom((Class) dirty.next()))
|
||||
for (Iterator<Class<?>> dirty = deleted.iterator(); dirty.hasNext();)
|
||||
if (accClass.isAssignableFrom(dirty.next()))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1401,8 +1402,8 @@ public class QueryImpl
|
|||
assertOpen();
|
||||
|
||||
RemoveOnCloseResultList res;
|
||||
for (Iterator itr = _resultLists.iterator(); itr.hasNext();) {
|
||||
res = (RemoveOnCloseResultList) itr.next();
|
||||
for (Iterator<RemoveOnCloseResultList> itr = _resultLists.iterator(); itr.hasNext();) {
|
||||
res = itr.next();
|
||||
if (force || res.isProviderOpen())
|
||||
res.close(false);
|
||||
}
|
||||
|
@ -1470,9 +1471,9 @@ public class QueryImpl
|
|||
// don't share mutable objects
|
||||
_fc.copy(q._fc);
|
||||
if (q._filtListeners != null)
|
||||
_filtListeners = new HashMap(q._filtListeners);
|
||||
_filtListeners = new HashMap<String,FilterListener>(q._filtListeners);
|
||||
if (q._aggListeners != null)
|
||||
_aggListeners = new HashMap(q._aggListeners);
|
||||
_aggListeners = new HashMap<String,AggregateListener>(q._aggListeners);
|
||||
return true;
|
||||
} finally {
|
||||
unlock();
|
||||
|
@ -1500,7 +1501,7 @@ public class QueryImpl
|
|||
}
|
||||
}
|
||||
|
||||
public Class[] getProjectionTypes() {
|
||||
public Class<?>[] getProjectionTypes() {
|
||||
lock();
|
||||
try {
|
||||
return compileForExecutor().getProjectionTypes(_storeQuery);
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
package org.apache.openjpa.persistence.jdbc;
|
||||
|
||||
import org.apache.openjpa.jdbc.kernel.EagerFetchModes;
|
||||
import org.apache.openjpa.kernel.FetchConfiguration;
|
||||
import org.apache.openjpa.persistence.OpenJPAEnum;
|
||||
|
||||
/**
|
||||
* Type of fetching to employ.
|
||||
|
@ -27,18 +29,20 @@ import org.apache.openjpa.jdbc.kernel.EagerFetchModes;
|
|||
* @since 0.4.0
|
||||
* @published
|
||||
*/
|
||||
public enum FetchMode {
|
||||
NONE(EagerFetchModes.EAGER_NONE),
|
||||
JOIN(EagerFetchModes.EAGER_JOIN),
|
||||
PARALLEL(EagerFetchModes.EAGER_PARALLEL);
|
||||
public enum FetchMode implements OpenJPAEnum<FetchMode>{
|
||||
NONE(EagerFetchModes.EAGER_NONE, "none"),
|
||||
JOIN(EagerFetchModes.EAGER_JOIN, "join"),
|
||||
PARALLEL(EagerFetchModes.EAGER_PARALLEL, "parallel");
|
||||
|
||||
private final int eagerFetchConstant;
|
||||
private final String[] _names;
|
||||
|
||||
private FetchMode(int value) {
|
||||
private FetchMode(int value, String... names) {
|
||||
eagerFetchConstant = value;
|
||||
_names = names;
|
||||
}
|
||||
|
||||
int toKernelConstant() {
|
||||
public int toKernelConstant() {
|
||||
return eagerFetchConstant;
|
||||
}
|
||||
|
||||
|
@ -57,4 +61,27 @@ public enum FetchMode {
|
|||
throw new IllegalArgumentException(kernelConstant + "");
|
||||
}
|
||||
}
|
||||
|
||||
public int convertToKernelConstant(String s) {
|
||||
return FetchMode.toKernelConstantFromString(s);
|
||||
}
|
||||
|
||||
public int convertToKernelConstant(int i) {
|
||||
if (i == FetchConfiguration.DEFAULT)
|
||||
return i;
|
||||
for (FetchMode mode : FetchMode.values()) {
|
||||
if (mode.eagerFetchConstant == i)
|
||||
return i;
|
||||
}
|
||||
throw new IllegalArgumentException(i + " is invalid value for FetchMode");
|
||||
}
|
||||
|
||||
public static int toKernelConstantFromString(String s) {
|
||||
for (FetchMode level : FetchMode.values()) {
|
||||
for (String name : level._names)
|
||||
if (name.equalsIgnoreCase(s) || String.valueOf(level.toKernelConstant()).equals(s))
|
||||
return level.toKernelConstant();
|
||||
}
|
||||
throw new IllegalArgumentException(s + " is not a valid name for " + FetchMode.class.getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,14 +18,21 @@
|
|||
*/
|
||||
package org.apache.openjpa.persistence.jdbc;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.LockModeType;
|
||||
|
||||
import org.apache.openjpa.jdbc.kernel.DelegatingJDBCFetchConfiguration;
|
||||
import org.apache.openjpa.jdbc.kernel.EagerFetchModes;
|
||||
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
|
||||
import org.apache.openjpa.jdbc.sql.JoinSyntaxes;
|
||||
import org.apache.openjpa.kernel.DelegatingFetchConfiguration;
|
||||
import org.apache.openjpa.kernel.FetchConfiguration;
|
||||
import org.apache.openjpa.persistence.FetchPlanImpl;
|
||||
import org.apache.openjpa.persistence.HintValueConverter;
|
||||
import org.apache.openjpa.persistence.PersistenceExceptions;
|
||||
|
||||
/**
|
||||
|
@ -40,6 +47,49 @@ public class JDBCFetchPlanImpl
|
|||
implements JDBCFetchPlan {
|
||||
|
||||
private DelegatingJDBCFetchConfiguration _fetch;
|
||||
static {
|
||||
registerHint(new String[]{"openjpa.FetchPlan.EagerFetchMode", "openjpa.jdbc.EagerFetchMode"},
|
||||
new HintValueConverter.StringToInteger(new String[]{"none", "0", "join", "1", "parallel", "2"},
|
||||
new int[]{EagerFetchModes.EAGER_NONE, EagerFetchModes.EAGER_NONE,
|
||||
EagerFetchModes.EAGER_JOIN, EagerFetchModes.EAGER_JOIN,
|
||||
EagerFetchModes.EAGER_PARALLEL,EagerFetchModes.EAGER_PARALLEL}),
|
||||
new HintValueConverter.EnumToInteger(FetchMode.class,
|
||||
new int[]{EagerFetchModes.EAGER_NONE, EagerFetchModes.EAGER_JOIN, EagerFetchModes.EAGER_PARALLEL}));
|
||||
registerHint(new String[]{"openjpa.JoinSyntax", "openjpa.jdbc.JoinSyntax","openjpa.FetchPlan.JoinSyntax"},
|
||||
new HintValueConverter.EnumToInteger(JoinSyntax.class,
|
||||
new int[]{JoinSyntaxes.SYNTAX_SQL92, JoinSyntaxes.SYNTAX_TRADITIONAL, JoinSyntaxes.SYNTAX_DATABASE}),
|
||||
new HintValueConverter.StringToInteger(new String[]{"sql92", "0", "traditional", "1", "database", "2"},
|
||||
new int[]{JoinSyntaxes.SYNTAX_SQL92, JoinSyntaxes.SYNTAX_SQL92,
|
||||
JoinSyntaxes.SYNTAX_TRADITIONAL, JoinSyntaxes.SYNTAX_TRADITIONAL,
|
||||
JoinSyntaxes.SYNTAX_DATABASE, JoinSyntaxes.SYNTAX_DATABASE}));
|
||||
registerHint(new String[]{"openjpa.FetchDirection", "openjpa.jdbc.FetchDirection",
|
||||
"openjpa.FetchPlan.FetchDirection"},
|
||||
new HintValueConverter.EnumToInteger(FetchDirection.class,
|
||||
new int[]{ResultSet.FETCH_FORWARD, ResultSet.FETCH_REVERSE, ResultSet.FETCH_UNKNOWN}),
|
||||
new HintValueConverter.StringToInteger(new String[]{"forward", String.valueOf(ResultSet.FETCH_FORWARD),
|
||||
"reverse", String.valueOf(ResultSet.FETCH_REVERSE),
|
||||
"unknown", String.valueOf(ResultSet.FETCH_UNKNOWN)},
|
||||
new int[]{ResultSet.FETCH_FORWARD, ResultSet.FETCH_FORWARD,
|
||||
ResultSet.FETCH_REVERSE, ResultSet.FETCH_REVERSE,
|
||||
ResultSet.FETCH_UNKNOWN, ResultSet.FETCH_UNKNOWN}));
|
||||
registerHint(new String[]{"openjpa.FetchPlan.Isolation", "openjpa.jdbc.TransactionIsolation"},
|
||||
new HintValueConverter.OpenJPAEnumToInteger(IsolationLevel.DEFAULT));
|
||||
registerHint(new String[]{"openjpa.FetchPlan.LRSSizeAlgorithm", "openjpa.FetchPlan.LRSSize",
|
||||
"openjpa.jdbc.LRSSize"},
|
||||
new HintValueConverter.OpenJPAEnumToInteger(LRSSizeAlgorithm.QUERY));
|
||||
registerHint(new String[]{"openjpa.FetchPlan.ResultSetType", "openjpa.jdbc.ResultSetType"},
|
||||
new HintValueConverter.OpenJPAEnumToInteger(ResultSetType.FORWARD_ONLY));
|
||||
registerHint(new String[]{"openjpa.FetchPlan.SubclassFetchMode", "openjpa.jdbc.SubclassFetchMode"},
|
||||
new HintValueConverter.OpenJPAEnumToInteger(FetchMode.NONE));
|
||||
|
||||
// "openjpa.FetchPlan.FetchDirection"
|
||||
// _hints.add("openjpa.FetchPlan.LockScope");
|
||||
// _hints.add("openjpa.FetchPlan.LockTimeout");
|
||||
// _hints.add("openjpa.FetchPlan.MaxFetchDepth");
|
||||
// _hints.add("openjpa.FetchPlan.QueryTimeout");
|
||||
// _hints.add("openjpa.FetchPlan.ReadLockMode");
|
||||
// _hints.add("openjpa.FetchPlan.WriteLockMode");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor; supply delegate.
|
||||
|
|
|
@ -20,13 +20,16 @@ package org.apache.openjpa.persistence.jdbc;
|
|||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import org.apache.openjpa.kernel.FetchConfiguration;
|
||||
import org.apache.openjpa.persistence.OpenJPAEnum;
|
||||
|
||||
/**
|
||||
* Type of result set to use.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @published
|
||||
*/
|
||||
public enum ResultSetType {
|
||||
public enum ResultSetType implements OpenJPAEnum<ResultSetType>{
|
||||
FORWARD_ONLY(ResultSet.TYPE_FORWARD_ONLY),
|
||||
SCROLL_INSENSITIVE(ResultSet.TYPE_SCROLL_INSENSITIVE),
|
||||
SCROLL_SENSITIVE(ResultSet.TYPE_SCROLL_SENSITIVE);
|
||||
|
@ -37,7 +40,7 @@ public enum ResultSetType {
|
|||
resultSetConstant = value;
|
||||
}
|
||||
|
||||
int toKernelConstant() {
|
||||
public int toKernelConstant() {
|
||||
return resultSetConstant;
|
||||
}
|
||||
|
||||
|
@ -56,4 +59,26 @@ public enum ResultSetType {
|
|||
throw new IllegalArgumentException(kernelConstant + "");
|
||||
}
|
||||
}
|
||||
|
||||
public int convertToKernelConstant(String s) {
|
||||
return ResultSetType.toKernelConstantFromString(s);
|
||||
}
|
||||
|
||||
public int convertToKernelConstant(int i) {
|
||||
if (i == FetchConfiguration.DEFAULT)
|
||||
return i;
|
||||
for (ResultSetType level : ResultSetType.values()) {
|
||||
if (level.resultSetConstant == i)
|
||||
return i;
|
||||
}
|
||||
throw new IllegalArgumentException(i + " is invalid value for ResultSetType");
|
||||
}
|
||||
|
||||
public static int toKernelConstantFromString(String s) {
|
||||
for (ResultSetType level : ResultSetType.values()) {
|
||||
if (level.name().equalsIgnoreCase(s) || String.valueOf(level.toKernelConstant()).equals(s))
|
||||
return level.toKernelConstant();
|
||||
}
|
||||
throw new IllegalArgumentException(s + " is not a valid name for " + ResultSetType.class.getName());
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1633,7 +1633,10 @@ public class EntityManagerImpl
|
|||
LockModeType lock, boolean requiresTxn) {
|
||||
// handle properties in map first
|
||||
configureCurrentCacheModes(fetch, properties);
|
||||
fetch.addHints(properties);
|
||||
if (properties != null) {
|
||||
for (Map.Entry<String, Object> entry : properties.entrySet())
|
||||
fetch.setHint(entry.getKey(), entry.getValue());
|
||||
}
|
||||
// override with the specific lockMode, if needed.
|
||||
if (lock != null && lock != LockModeType.NONE) {
|
||||
if (requiresTxn) {
|
||||
|
|
|
@ -1,212 +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
|
||||
*
|
||||
* http://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.openjpa.persistence;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.LockModeType;
|
||||
|
||||
import org.apache.openjpa.kernel.FetchConfigurationImpl;
|
||||
import org.apache.openjpa.kernel.AbstractHintHandler;
|
||||
import org.apache.openjpa.kernel.MixedLockLevels;
|
||||
import org.apache.openjpa.lib.conf.ProductDerivations;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
|
||||
/**
|
||||
* Fetch plan hint handler. Handles openjpa.FetchPlan.*,
|
||||
* javax.persistence.lock.* and javax.persistence.query.* hints.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @nojavadoc
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class FetchPlanHintHandler extends AbstractHintHandler {
|
||||
|
||||
private static final Localizer _loc = Localizer.forPackage(FetchPlanHintHandler.class);
|
||||
|
||||
protected static final String PREFIX_FETCHPLAN = PREFIX_OPENJPA + "FetchPlan.";
|
||||
|
||||
// Valid defined product derivation prefixes
|
||||
protected static final Set<String> validProductPrefixes = new HashSet<String>();
|
||||
// JPA Specification 2.0 keys are mapped to equivalent FetchPlan keys
|
||||
protected static final Map<String, String> javaxHintsMap = new HashMap<String, String>();
|
||||
// hints precedent definitions
|
||||
protected static final Map<String, String[]> precedenceMap = new HashMap<String, String[]>();
|
||||
|
||||
static {
|
||||
// Initialize valid product prefixes from available product derivations.
|
||||
for (String prefix : ProductDerivations.getConfigurationPrefixes()) {
|
||||
validProductPrefixes.add(prefix);
|
||||
}
|
||||
// Initialize javax.persistence to openjpa.FetchPlan hint mapping.
|
||||
javaxHintsMap.put(JPAProperties.LOCK_TIMEOUT, PREFIX_FETCHPLAN + "LockTimeout");
|
||||
javaxHintsMap.put(JPAProperties.LOCK_SCOPE, PREFIX_FETCHPLAN + "LockScope");
|
||||
javaxHintsMap.put(JPAProperties.QUERY_TIMEOUT, PREFIX_FETCHPLAN + "QueryTimeout");
|
||||
// Initialize hint precedence order mapping from list.
|
||||
String[][] precedenceMapList = {
|
||||
{ JPAProperties.LOCK_TIMEOUT,
|
||||
PREFIX_FETCHPLAN + "LockTimeout",
|
||||
PREFIX_OPENJPA + "LockTimeout" },
|
||||
|
||||
{ JPAProperties.LOCK_SCOPE,
|
||||
PREFIX_FETCHPLAN + "LockScope",
|
||||
PREFIX_OPENJPA + "LockScope" },
|
||||
|
||||
{ JPAProperties.QUERY_TIMEOUT,
|
||||
PREFIX_FETCHPLAN + "QueryTimeout",
|
||||
PREFIX_OPENJPA + "QueryTimeout" },
|
||||
|
||||
{ PREFIX_FETCHPLAN + "Isolation",
|
||||
PREFIX_JDBC + "TransactionIsolation" },
|
||||
|
||||
{ PREFIX_FETCHPLAN + "EagerFetchMode",
|
||||
PREFIX_JDBC + "EagerFetchMode" },
|
||||
|
||||
{ PREFIX_FETCHPLAN + "FetchDirection",
|
||||
PREFIX_JDBC + "FetchDirection" },
|
||||
|
||||
{ PREFIX_FETCHPLAN + "JoinSyntax",
|
||||
PREFIX_JDBC + "JoinSyntax" },
|
||||
|
||||
{ PREFIX_FETCHPLAN + "LRSSizeAlgorithm",
|
||||
PREFIX_FETCHPLAN + "LRSSize",
|
||||
PREFIX_JDBC + "LRSSize" },
|
||||
|
||||
{ PREFIX_FETCHPLAN + "ResultSetType",
|
||||
PREFIX_JDBC + "ResultSetType" },
|
||||
|
||||
{ PREFIX_FETCHPLAN + "SubclassFetchMode",
|
||||
PREFIX_JDBC + "SubclassFetchMode" },
|
||||
|
||||
{ PREFIX_FETCHPLAN + "ReadLockMode",
|
||||
PREFIX_OPENJPA + "ReadLockLevel" },
|
||||
|
||||
{ PREFIX_FETCHPLAN + "WriteLockMode",
|
||||
PREFIX_OPENJPA + "WriteLockLevel" },
|
||||
|
||||
{ PREFIX_FETCHPLAN + "FetchBatchSize",
|
||||
PREFIX_OPENJPA + "FetchBatchSize" },
|
||||
|
||||
{ PREFIX_FETCHPLAN + "MaxFetchDepth",
|
||||
PREFIX_OPENJPA + "MaxFetchDepth" }
|
||||
};
|
||||
for (String[] list : precedenceMapList) {
|
||||
for (String hint : list)
|
||||
precedenceMap.put(hint, list);
|
||||
}
|
||||
}
|
||||
|
||||
protected FetchPlanImpl _fPlan;
|
||||
|
||||
/**
|
||||
* Constructor; supply delegate.
|
||||
*/
|
||||
public FetchPlanHintHandler(FetchPlanImpl fetchPlan) {
|
||||
super((FetchConfigurationImpl) fetchPlan.getDelegate());
|
||||
_fPlan = fetchPlan;
|
||||
}
|
||||
|
||||
public boolean setHint(String hintName, Object value, boolean validateThrowException) {
|
||||
if (!JPAProperties.isValidKey(hintName)
|
||||
&& !validProductPrefixes.contains(getPrefixOf(hintName)))
|
||||
return false;
|
||||
return super.setHint(hintName, value, validateThrowException);
|
||||
}
|
||||
|
||||
protected boolean setHintInternal(String hintName, Object value, boolean validateThrowException) {
|
||||
boolean valueSet = false;
|
||||
if (hintName.startsWith(PREFIX_FETCHPLAN)) {
|
||||
if (hintName.endsWith("LockMode") && !_fConfig.getContext().isActive()) {
|
||||
_fConfig.setHint(hintName + ".Defer", toLockLevel(value));
|
||||
valueSet = true;
|
||||
} else {
|
||||
valueSet = hintToSetter(_fPlan, hintName, value);
|
||||
}
|
||||
} else {
|
||||
_fConfig.setHint(hintName, value, validateThrowException);
|
||||
}
|
||||
return valueSet;
|
||||
}
|
||||
|
||||
protected String hintToKey(String key) {
|
||||
// transform product derived prefix to openjpa prefix
|
||||
if (!key.startsWith(PREFIX_OPENJPA)
|
||||
&& validProductPrefixes.contains(getPrefixOf(key)))
|
||||
key = PREFIX_OPENJPA + key.substring(key.indexOf('.') + 1);
|
||||
|
||||
// transform javax.persistence.* hints to fetch plan hints.
|
||||
if (javaxHintsMap.containsKey(key))
|
||||
key = javaxHintsMap.get(key);
|
||||
return key;
|
||||
}
|
||||
|
||||
protected boolean hasPrecedent(String key) {
|
||||
boolean hasPrecedent = true;
|
||||
String[] list = precedenceMap.get(key);
|
||||
if (list != null) {
|
||||
for (String hint : list) {
|
||||
if (hint.equals(key))
|
||||
break;
|
||||
// stop if a higher precedence hint has already defined
|
||||
if (_fConfig.getHint(hint) != null) {
|
||||
hasPrecedent = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasPrecedent;
|
||||
}
|
||||
|
||||
protected void handleException(RuntimeException e) {
|
||||
throw PersistenceExceptions.toPersistenceException(e);
|
||||
}
|
||||
|
||||
private Integer toLockLevel(Object value) {
|
||||
Object origValue = value;
|
||||
if (value instanceof String) {
|
||||
// to accomodate alias name input in relationship with enum values
|
||||
// e.g. "optimistic-force-increment" ==
|
||||
// LockModeType.OPTIMISTIC_FORCE_INCREMENT
|
||||
String strValue = ((String) value).toUpperCase().replace('-', '_');
|
||||
value = Enum.valueOf(LockModeType.class, strValue);
|
||||
}
|
||||
if (value instanceof LockModeType)
|
||||
value = MixedLockLevelsHelper.toLockLevel((LockModeType) value);
|
||||
|
||||
Integer intValue = null;
|
||||
if (value instanceof Integer)
|
||||
intValue = (Integer) value;
|
||||
if (intValue == null
|
||||
|| (intValue != MixedLockLevels.LOCK_NONE
|
||||
&& intValue != MixedLockLevels.LOCK_READ
|
||||
&& intValue != MixedLockLevels.LOCK_OPTIMISTIC
|
||||
&& intValue != MixedLockLevels.LOCK_WRITE
|
||||
&& intValue != MixedLockLevels.LOCK_OPTIMISTIC_FORCE_INCREMENT
|
||||
&& intValue != MixedLockLevels.LOCK_PESSIMISTIC_READ
|
||||
&& intValue != MixedLockLevels.LOCK_PESSIMISTIC_WRITE
|
||||
&& intValue != MixedLockLevels.LOCK_PESSIMISTIC_FORCE_INCREMENT)
|
||||
)
|
||||
throw new IllegalArgumentException(_loc.get("bad-lock-level",
|
||||
origValue).getMessage());
|
||||
return intValue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.openjpa.persistence;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* Converts a given user-specified value to a target type consumable by the kernel.
|
||||
* Used by hint processing.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
* @since 2.0.0
|
||||
* @unpublished
|
||||
*/
|
||||
public interface HintValueConverter {
|
||||
/**
|
||||
* Convert the user-specified value to a kernel consumable value.
|
||||
*
|
||||
* @param original the user-specified value
|
||||
* @return an equivalent value consumable by a kernel construct.
|
||||
*
|
||||
* @exception IllegalArgumentException if the given value can not be converted.
|
||||
*/
|
||||
Object convert(Object original);
|
||||
|
||||
/**
|
||||
* Affirm if this receiver can convert the value of the given type.
|
||||
*/
|
||||
boolean canConvert(Class<?> type);
|
||||
|
||||
/**
|
||||
* Convert the enum value to an enumerated set of constants.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
static class EnumToInteger implements HintValueConverter {
|
||||
private Class<? extends Enum<?>> _type;
|
||||
private Integer[] map;
|
||||
|
||||
public EnumToInteger(Class<? extends Enum<?>> enumType, int[] numbers) {
|
||||
try {
|
||||
_type = enumType;
|
||||
Enum<?>[] values = (Enum<?>[])enumType.getMethod("values", null).invoke(null, (Class<?>[])null);
|
||||
map = new Integer[values.length];
|
||||
int i = 0;
|
||||
for (Enum<?> v : values) {
|
||||
map[v.ordinal()] = numbers[i++];
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Object convert(Object e) {
|
||||
if (e.getClass() == _type)
|
||||
return map[((Enum<?>)e).ordinal()];
|
||||
return e;
|
||||
}
|
||||
|
||||
public boolean canConvert(Class<?> type) {
|
||||
return Enum.class.isAssignableFrom(type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an OpenJPA specific enum to an equivalent kernel constant.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public static class OpenJPAEnumToInteger implements HintValueConverter {
|
||||
private OpenJPAEnum<?> _prototype;
|
||||
|
||||
public OpenJPAEnumToInteger(OpenJPAEnum<?> prototype) {
|
||||
_prototype = prototype;
|
||||
}
|
||||
|
||||
public Object convert(Object e) {
|
||||
if (e.getClass() == _prototype.getClass())
|
||||
return ((OpenJPAEnum<Enum<?>>)e).toKernelConstant();
|
||||
if (e instanceof String) {
|
||||
return _prototype.convertToKernelConstant(e.toString());
|
||||
}
|
||||
if (e instanceof Integer) {
|
||||
return _prototype.convertToKernelConstant((Integer)e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
public boolean canConvert(Class<?> type) {
|
||||
return OpenJPAEnum.class.isAssignableFrom(type)
|
||||
|| type == String.class
|
||||
|| type == Integer.class
|
||||
|| type == int.class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String to an integer.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public static class StringToInteger implements HintValueConverter {
|
||||
private String[] strings;
|
||||
private Integer[] numbers;
|
||||
|
||||
/**
|
||||
* Construct a converter that will simply translate a numeric string to a integer.
|
||||
*/
|
||||
public StringToInteger() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a converter that will translate any of the given strings to corresponding integer.
|
||||
* Both arrays must not be null, must not contain null elements and must have the same dimension.
|
||||
*
|
||||
* @param strings
|
||||
* @param numbers
|
||||
*/
|
||||
public StringToInteger(String[] strings, int[] numbers) {
|
||||
if (strings == null || numbers == null || strings.length != numbers.length)
|
||||
throw new IllegalArgumentException();
|
||||
this.strings = new String[strings.length];
|
||||
this.numbers = new Integer[numbers.length];
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
this.strings[i] = strings[i];
|
||||
this.numbers[i] = numbers[i];
|
||||
}
|
||||
}
|
||||
|
||||
public Object convert(Object s) {
|
||||
if (s instanceof String == false)
|
||||
return s;
|
||||
String str = s.toString();
|
||||
if (strings == null) {
|
||||
try {
|
||||
return Integer.parseInt(str);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Can not convert " + str + " . Expected a numeric string");
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
if (strings[i].equalsIgnoreCase(str))
|
||||
return numbers[i];
|
||||
}
|
||||
throw new IllegalArgumentException("Can not convert " + str + " . Valid input is " +
|
||||
Arrays.toString(strings));
|
||||
}
|
||||
|
||||
public boolean canConvert(Class<?> cls) {
|
||||
return String.class == cls;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StringToBoolean implements HintValueConverter {
|
||||
public Object convert(Object v) {
|
||||
if (v instanceof String)
|
||||
return Boolean.valueOf(v.toString());
|
||||
if (v instanceof Boolean)
|
||||
return v;
|
||||
return v;
|
||||
}
|
||||
|
||||
public boolean canConvert(Class<?> cls) {
|
||||
return String.class == cls || Boolean.class == cls || boolean.class == cls;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -20,6 +20,7 @@ package org.apache.openjpa.persistence;
|
|||
|
||||
import javax.persistence.LockModeType;
|
||||
|
||||
import org.apache.openjpa.kernel.FetchConfiguration;
|
||||
import org.apache.openjpa.kernel.MixedLockLevels;
|
||||
|
||||
/**
|
||||
|
@ -29,7 +30,7 @@ import org.apache.openjpa.kernel.MixedLockLevels;
|
|||
* @author Albert Lee
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class MixedLockLevelsHelper {
|
||||
public class MixedLockLevelsHelper implements HintValueConverter {
|
||||
/**
|
||||
* Translates javax.persistence LockModeType to internal lock level.
|
||||
*/
|
||||
|
@ -51,6 +52,24 @@ public class MixedLockLevelsHelper {
|
|||
return MixedLockLevels.LOCK_PESSIMISTIC_FORCE_INCREMENT;
|
||||
}
|
||||
|
||||
public static int toLockLevel(int mode) {
|
||||
switch (mode) {
|
||||
case MixedLockLevels.LOCK_OPTIMISTIC:
|
||||
case MixedLockLevels.LOCK_OPTIMISTIC_FORCE_INCREMENT:
|
||||
case MixedLockLevels.LOCK_PESSIMISTIC_FORCE_INCREMENT:
|
||||
case MixedLockLevels.LOCK_PESSIMISTIC_READ:
|
||||
case MixedLockLevels.LOCK_PESSIMISTIC_WRITE:
|
||||
case MixedLockLevels.LOCK_NONE:
|
||||
case MixedLockLevels.LOCK_READ:
|
||||
case MixedLockLevels.LOCK_WRITE:
|
||||
case FetchConfiguration.DEFAULT:
|
||||
return mode;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown lock level " + mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translates internal lock level to javax.persistence LockModeType.
|
||||
*/
|
||||
|
@ -71,4 +90,30 @@ public class MixedLockLevelsHelper {
|
|||
return LockModeType.PESSIMISTIC_WRITE;
|
||||
return LockModeType.PESSIMISTIC_FORCE_INCREMENT;
|
||||
}
|
||||
|
||||
public boolean canConvert(Class<?> type) {
|
||||
return type == LockModeType.class || type == String.class || type == Integer.class || type == int.class;
|
||||
}
|
||||
|
||||
public Object convert(Object original) {
|
||||
if (original instanceof LockModeType)
|
||||
return MixedLockLevelsHelper.toLockLevel((LockModeType)original);
|
||||
if (original instanceof String) {
|
||||
try {
|
||||
int value = Integer.parseInt(original.toString());
|
||||
return MixedLockLevelsHelper.toLockLevel(value);
|
||||
} catch (NumberFormatException nfe) {
|
||||
if ("none".equalsIgnoreCase(original.toString())) {
|
||||
return MixedLockLevels.LOCK_NONE;
|
||||
}
|
||||
return MixedLockLevelsHelper.toLockLevel(
|
||||
LockModeType.valueOf(original.toString().toUpperCase().replace('-', '_')));
|
||||
}
|
||||
}
|
||||
if (original instanceof Integer) {
|
||||
return MixedLockLevelsHelper.toLockLevel((Integer)original);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("can not convert " + original + " of " + original.getClass());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,16 +29,17 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.spi.PersistenceUnitInfo;
|
||||
import javax.persistence.spi.PersistenceUnitTransactionType;
|
||||
import javax.persistence.SharedCacheMode;
|
||||
import javax.persistence.ValidationMode;
|
||||
import javax.persistence.spi.PersistenceUnitInfo;
|
||||
import javax.persistence.spi.PersistenceUnitTransactionType;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.openjpa.conf.Compatibility;
|
||||
|
@ -48,6 +49,7 @@ import org.apache.openjpa.conf.OpenJPAProductDerivation;
|
|||
import org.apache.openjpa.conf.Specification;
|
||||
import org.apache.openjpa.datacache.DataCacheMode;
|
||||
import org.apache.openjpa.kernel.MixedLockLevels;
|
||||
import org.apache.openjpa.kernel.QueryHints;
|
||||
import org.apache.openjpa.lib.conf.AbstractProductDerivation;
|
||||
import org.apache.openjpa.lib.conf.Configuration;
|
||||
import org.apache.openjpa.lib.conf.ConfigurationProvider;
|
||||
|
@ -94,9 +96,55 @@ public class PersistenceProductDerivation
|
|||
private HashMap<String, PUNameCollision> _puNameCollisions
|
||||
= new HashMap<String,PUNameCollision>();
|
||||
|
||||
public static final String PREFIX = "javax.persistence";
|
||||
|
||||
private static Set<String> _hints = new HashSet<String>();
|
||||
|
||||
// Provider name to filter out PUs that don't belong to this derivation.
|
||||
protected String _providerImplName;
|
||||
|
||||
static {
|
||||
_hints.add("javax.persistence.lock.timeout");
|
||||
_hints.add("javax.persistence.query.timeout");
|
||||
|
||||
_hints.add("openjpa.FetchPlan.ExtendedPathLookup");
|
||||
_hints.add("openjpa.FetchBatchSize");
|
||||
_hints.add("openjpa.FetchPlan.FetchBatchSize");
|
||||
_hints.add("openjpa.MaxFetchDepth");
|
||||
_hints.add("openjpa.FetchPlan.MaxFetchDepth");
|
||||
_hints.add("openjpa.LockTimeout");
|
||||
_hints.add("openjpa.FetchPlan.LockTimeout");
|
||||
_hints.add("openjpa.QueryTimeout");
|
||||
_hints.add("openjpa.FetchPlan.QueryTimeout");
|
||||
_hints.add("openjpa.FlushBeforeQueries");
|
||||
_hints.add("openjpa.FetchPlan.FlushBeforeQueries");
|
||||
_hints.add("openjpa.ReadLockLevel");
|
||||
_hints.add("openjpa.FetchPlan.ReadLockLevel");
|
||||
_hints.add("openjpa.WriteLockLevel");
|
||||
_hints.add("openjpa.FetchPlan.WriteLockLevel");
|
||||
_hints.add("openjpa.FetchPlan.FetchBatchSize");
|
||||
_hints.add("openjpa.FetchPlan.LockScope");
|
||||
_hints.add("openjpa.FetchPlan.LockTimeout");
|
||||
_hints.add("openjpa.FetchPlan.MaxFetchDepth");
|
||||
_hints.add("openjpa.FetchPlan.QueryTimeout");
|
||||
_hints.add("openjpa.FetchPlan.ReadLockMode");
|
||||
_hints.add("openjpa.FetchPlan.WriteLockMode");
|
||||
_hints.add(QueryHints.HINT_AGGREGATE_LISTENER);
|
||||
_hints.add(QueryHints.HINT_AGGREGATE_LISTENERS);
|
||||
_hints.add(QueryHints.HINT_FILTER_LISTENER);
|
||||
_hints.add(QueryHints.HINT_FILTER_LISTENERS);
|
||||
_hints.add(QueryHints.HINT_IGNORE_FINDER);
|
||||
_hints.add(QueryHints.HINT_IGNORE_PREPARED_QUERY);
|
||||
_hints.add(QueryHints.HINT_INVALIDATE_FINDER);
|
||||
_hints.add(QueryHints.HINT_INVALIDATE_PREPARED_QUERY);
|
||||
_hints.add(QueryHints.HINT_PARAM_MARKER_IN_QUERY);
|
||||
_hints.add(QueryHints.HINT_RECACHE_FINDER);
|
||||
_hints.add(QueryHints.HINT_RESULT_COUNT);
|
||||
_hints.add(QueryHints.HINT_SUBCLASSES);
|
||||
|
||||
_hints = Collections.unmodifiableSet(_hints);
|
||||
}
|
||||
|
||||
public PersistenceProductDerivation() {
|
||||
_providerImplName = PersistenceProviderImpl.class.getName();
|
||||
}
|
||||
|
@ -110,7 +158,12 @@ public class PersistenceProductDerivation
|
|||
|
||||
@Override
|
||||
public String getConfigurationPrefix() {
|
||||
return "javax.persistence";
|
||||
return PREFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedQueryHints() {
|
||||
return _hints;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue