From b44db2f7754c785da44f084849e7caac9ff216e9 Mon Sep 17 00:00:00 2001 From: rsandtner Date: Fri, 4 Mar 2016 14:44:25 +0100 Subject: [PATCH 1/2] OPENJPA-2632 use TCCL as fallback --- .../main/java/org/apache/openjpa/kernel/QueryImpl.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java index 4f36a28be3..d66627e16e 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java @@ -1695,8 +1695,14 @@ private Class toClass(String name) { getClassLoader(_class, _broker.getClassLoader()); try { return Strings.toClass(name, _loader); - } catch (RuntimeException re) { - } catch (NoClassDefFoundError ncdfe) { + } catch (IllegalArgumentException e) { + // because Strings.toClass catches Throwable (wtf?) and throws an IllegalArgumentExcpetion + + try { + return Strings.toClass(name, null); // -> null forces TCCL.. + } catch (IllegalArgumentException iae) { + // was just a try, lets ignore it + } } return null; } From 9779092374eacb10bd012a0964fe907522a5a022 Mon Sep 17 00:00:00 2001 From: rsandtner Date: Mon, 7 Mar 2016 13:53:15 +0100 Subject: [PATCH 2/2] OPENJPA-2632 use TCCL only for select new introduced new property to enable this feature --- .../openjpa/conf/OpenJPAConfiguration.java | 34 +++++++++++++++++++ .../conf/OpenJPAConfigurationImpl.java | 23 +++++++++++++ .../org/apache/openjpa/kernel/QueryImpl.java | 12 ++----- .../kernel/jpql/JPQLExpressionBuilder.java | 18 ++++++++++ 4 files changed, 78 insertions(+), 9 deletions(-) diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java index 998bd0aca7..53f06574cf 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java @@ -219,6 +219,13 @@ public interface OpenJPAConfiguration public static final String OPTION_POSTLOAD_ON_MERGE = "openjpa.option.PostLoadOnMerge"; + /** + * Option to enable TCCL if the result class for select new is not found + * in the entities classloader + */ + public static final String OPTION_USE_TCCL_IN_SELECT_NEW = + "openjpa.option.UseTCCLinSelectNew"; + /** * Return the set of option strings supported by this runtime. This set * is mutable. @@ -1949,5 +1956,32 @@ public interface OpenJPAConfiguration * @since 2.2.0 */ public void setOptimizeIdCopy(Boolean optimizeIds); + + /** + * Indicates if the {@link Thread#contextClassLoader} should be used + * as fallback if the result class for {@code select new} is not found + * by the classloader of the entity. + * + * @since 2.4.2 + */ + public boolean getUseTCCLinSelectNew(); + + /** + * Indicates if the {@link Thread#contextClassLoader} should be used + * as fallback if the result class for {@code select new} is not found + * by the classloader of the entity. + * + * @since 2.4.2 + */ + public void setUseTCCLinSelectNew(boolean useTcclForSelectNew); + + /** + * Indicates if the {@link Thread#contextClassLoader} should be used + * as fallback if the result class for {@code select new} is not found + * by the classloader of the entity. + * + * @since 2.4.2 + */ + public void setUseTCCLinSelectNew(Boolean useTcclForSelectNew); } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java index d3a186c8fe..86e6a256d3 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java @@ -177,6 +177,7 @@ public class OpenJPAConfigurationImpl public PluginListValue instrumentationProviders; public BooleanValue postLoadOnMerge; public BooleanValue optimizeIdCopy; + public BooleanValue useTcclForSelectNew; // custom values public BrokerFactoryValue brokerFactoryPlugin; @@ -604,6 +605,10 @@ public OpenJPAConfigurationImpl(boolean derivations, boolean loadGlobals) { aliases = new String[] { "default", AuditLogger.class.getName(), }; auditorPlugin.setAliases(aliases); auditorPlugin.setInstantiatingGetter("getAuditorInstance"); + + useTcclForSelectNew = addBoolean("UseTCCLinSelectNew"); + useTcclForSelectNew.setDefault("false"); + useTcclForSelectNew.set(false); // initialize supported options that some runtimes may not support supportedOptions.add(OPTION_NONTRANS_READ); @@ -622,6 +627,7 @@ public OpenJPAConfigurationImpl(boolean derivations, boolean loadGlobals) { supportedOptions.add(OPTION_VALUE_INCREMENT); supportedOptions.add(OPTION_DATASTORE_CONNECTION); supportedOptions.add(OPTION_POSTLOAD_ON_MERGE); + supportedOptions.add(OPTION_USE_TCCL_IN_SELECT_NEW); if (derivations) ProductDerivations.beforeConfigurationLoad(this); @@ -1873,5 +1879,22 @@ public void setOptimizeIdCopy(Boolean optimizeId) { setOptimizeIdCopy(optimizeId.booleanValue()); } } + + @Override + public boolean getUseTCCLinSelectNew() { + return useTcclForSelectNew.get(); + } + + @Override + public void setUseTCCLinSelectNew(boolean useTcclForSelectNew) { + this.useTcclForSelectNew.set(useTcclForSelectNew); + } + + @Override + public void setUseTCCLinSelectNew(Boolean useTcclForSelectNew) { + if (useTcclForSelectNew != null) { + setUseTCCLinSelectNew(useTcclForSelectNew.booleanValue()); + } + } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java index d66627e16e..a83a82a41d 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java @@ -1692,17 +1692,11 @@ else if (importName.endsWith(".*")) { private Class toClass(String name) { if (_loader == null) _loader = _broker.getConfiguration().getClassResolverInstance(). - getClassLoader(_class, _broker.getClassLoader()); + getClassLoader(_class, _broker.getClassLoader()); try { return Strings.toClass(name, _loader); - } catch (IllegalArgumentException e) { - // because Strings.toClass catches Throwable (wtf?) and throws an IllegalArgumentExcpetion - - try { - return Strings.toClass(name, null); // -> null forces TCCL.. - } catch (IllegalArgumentException iae) { - // was just a try, lets ignore it - } + } catch (RuntimeException re) { + } catch (NoClassDefFoundError ncdfe) { } return null; } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java index 64470bd5fa..cf09da3a42 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java @@ -22,6 +22,7 @@ import java.io.Serializable; import java.lang.reflect.Field; import java.math.BigDecimal; +import java.security.AccessController; import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; @@ -56,6 +57,7 @@ import org.apache.openjpa.kernel.exps.Subquery; import org.apache.openjpa.kernel.exps.Value; import org.apache.openjpa.lib.log.Log; +import org.apache.openjpa.lib.util.J2DoPrivHelper; import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.OrderedMap; import org.apache.openjpa.lib.util.Localizer.Message; @@ -410,6 +412,22 @@ private void evalProjectionsResultShape(JPQLNode selectionsNode, String baseName = left(node).getChild(n-1).text; constructor = resolver.classForName(baseName, null); } + + if (constructor == null && resolver.getConfiguration().getUseTCCLinSelectNew()) { + try { + if (System.getSecurityManager() == null) { + constructor = AccessController.doPrivileged( + J2DoPrivHelper.getForNameAction(resultClassName, false, + AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction()))); + } + else { + constructor = Thread.currentThread().getContextClassLoader().loadClass(resultClassName); + } + } catch (Exception e) { + // ignore + } + } + if (constructor == null) throw parseException(EX_USER, "no-constructor", new Object[]{ resultClassName }, null);