Skip to content

Commit df9cf9f

Browse files
committed
HV-1577 Fix class loading issues
1 parent 6ed86fc commit df9cf9f

File tree

4 files changed

+65
-16
lines changed

4 files changed

+65
-16
lines changed

engine/src/main/java/org/hibernate/validator/internal/util/privilegedactions/LoadClass.java

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
* @author Hardy Ferentschik
2727
* @author Kevin Pollet <kevin.pollet@serli.com> (C) 2011 SERLI
2828
* @author Gunnar Morling
29+
* @author Guillaume Smet
2930
*/
3031
public final class LoadClass implements PrivilegedAction<Class<?>> {
3132

@@ -37,22 +38,32 @@ public final class LoadClass implements PrivilegedAction<Class<?>> {
3738

3839
private final ClassLoader classLoader;
3940

41+
private final ClassLoader initialThreadContextClassLoader;
42+
4043
/**
4144
* when true, it will check the Thread Context ClassLoader when the class is not found in the provided one
4245
*/
4346
private final boolean fallbackOnTCCL;
4447

4548
public static LoadClass action(String className, ClassLoader classLoader) {
46-
return new LoadClass( className, classLoader, true );
49+
return action( className, classLoader, true );
4750
}
4851

4952
public static LoadClass action(String className, ClassLoader classLoader, boolean fallbackOnTCCL) {
50-
return new LoadClass( className, classLoader, fallbackOnTCCL );
53+
return new LoadClass( className, classLoader, null, fallbackOnTCCL );
54+
}
55+
56+
/**
57+
* in some cases, the TCCL has been overridden so we need to pass it explicitly.
58+
*/
59+
public static LoadClass action(String className, ClassLoader classLoader, ClassLoader initialThreadContextClassLoader) {
60+
return new LoadClass( className, classLoader, initialThreadContextClassLoader, true );
5161
}
5262

53-
private LoadClass(String className, ClassLoader classLoader, boolean fallbackOnTCCL) {
63+
private LoadClass(String className, ClassLoader classLoader, ClassLoader initialThreadContextClassLoader, boolean fallbackOnTCCL) {
5464
this.className = className;
5565
this.classLoader = classLoader;
66+
this.initialThreadContextClassLoader = initialThreadContextClassLoader;
5667
this.fallbackOnTCCL = fallbackOnTCCL;
5768
}
5869

@@ -80,7 +91,9 @@ private Class<?> loadClassInValidatorNameSpace() {
8091
exception = e;
8192
}
8293
if ( fallbackOnTCCL ) {
83-
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
94+
ClassLoader contextClassLoader = initialThreadContextClassLoader != null
95+
? initialThreadContextClassLoader
96+
: Thread.currentThread().getContextClassLoader();
8497
if ( contextClassLoader != null ) {
8598
try {
8699
return Class.forName( className, false, contextClassLoader );
@@ -100,20 +113,22 @@ private Class<?> loadClassInValidatorNameSpace() {
100113

101114
private Class<?> loadNonValidatorClass() {
102115
Exception exception = null;
103-
try {
104-
if ( classLoader != null ) {
116+
if ( classLoader != null ) {
117+
try {
105118
return Class.forName( className, false, classLoader );
106119
}
107-
}
108-
catch (ClassNotFoundException e) {
109-
exception = e;
110-
}
111-
catch (RuntimeException e) {
112-
exception = e;
120+
catch (ClassNotFoundException e) {
121+
exception = e;
122+
}
123+
catch (RuntimeException e) {
124+
exception = e;
125+
}
113126
}
114127
if ( fallbackOnTCCL ) {
115128
try {
116-
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
129+
ClassLoader contextClassLoader = initialThreadContextClassLoader != null
130+
? initialThreadContextClassLoader
131+
: Thread.currentThread().getContextClassLoader();
117132
if ( contextClassLoader != null ) {
118133
return Class.forName( className, false, contextClassLoader );
119134
}

engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ClassLoadingHelper.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* types, qualified names or unqualified names (in which case a given default package will be assumed).
2121
*
2222
* @author Gunnar Morling
23+
* @author Guillaume Smet
2324
*/
2425
class ClassLoadingHelper {
2526

@@ -47,8 +48,11 @@ class ClassLoadingHelper {
4748

4849
private final ClassLoader externalClassLoader;
4950

50-
ClassLoadingHelper(ClassLoader externalClassLoader) {
51+
private final ClassLoader threadContextClassLoader;
52+
53+
ClassLoadingHelper(ClassLoader externalClassLoader, ClassLoader threadContextClassLoader) {
5154
this.externalClassLoader = externalClassLoader;
55+
this.threadContextClassLoader = threadContextClassLoader;
5256
}
5357

5458
Class<?> loadClass(String className, String defaultPackage) {
@@ -80,7 +84,7 @@ Class<?> loadClass(String className, String defaultPackage) {
8084
}
8185

8286
private Class<?> loadClass(String className) {
83-
return run( LoadClass.action( className, externalClassLoader ) );
87+
return run( LoadClass.action( className, externalClassLoader, threadContextClassLoader ) );
8488
}
8589

8690
private static boolean isArrayClassName(String className) {

engine/src/main/java/org/hibernate/validator/internal/xml/mapping/MappingXmlParser.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import java.io.IOException;
1313
import java.io.InputStream;
1414
import java.lang.invoke.MethodHandles;
15+
import java.security.AccessController;
16+
import java.security.PrivilegedAction;
1517
import java.util.Collections;
1618
import java.util.HashMap;
1719
import java.util.List;
@@ -32,6 +34,8 @@
3234
import org.hibernate.validator.internal.util.TypeResolutionHelper;
3335
import org.hibernate.validator.internal.util.logging.Log;
3436
import org.hibernate.validator.internal.util.logging.LoggerFactory;
37+
import org.hibernate.validator.internal.util.privilegedactions.GetClassLoader;
38+
import org.hibernate.validator.internal.util.privilegedactions.SetContextClassLoader;
3539
import org.hibernate.validator.internal.xml.CloseIgnoringInputStream;
3640
import org.hibernate.validator.internal.xml.XmlParserHelper;
3741
import org.xml.sax.SAXException;
@@ -79,7 +83,7 @@ public MappingXmlParser(ConstraintHelper constraintHelper, TypeResolutionHelper
7983
this.defaultSequences = newHashMap();
8084
this.constrainedElements = newHashMap();
8185
this.xmlParserHelper = new XmlParserHelper();
82-
this.classLoadingHelper = new ClassLoadingHelper( externalClassLoader );
86+
this.classLoadingHelper = new ClassLoadingHelper( externalClassLoader, run( GetClassLoader.fromContext() ) );
8387
}
8488

8589
/**
@@ -89,7 +93,11 @@ public MappingXmlParser(ConstraintHelper constraintHelper, TypeResolutionHelper
8993
* @param mappingStreams The streams to parse. Must support the mark/reset contract.
9094
*/
9195
public final void parse(Set<InputStream> mappingStreams) {
96+
ClassLoader previousTccl = run( GetClassLoader.fromContext() );
97+
9298
try {
99+
run( SetContextClassLoader.action( MappingXmlParser.class.getClassLoader() ) );
100+
93101
Set<String> alreadyProcessedConstraintDefinitions = newHashSet();
94102
for ( InputStream in : mappingStreams ) {
95103
// the InputStreams passed in parameters support mark and reset
@@ -128,6 +136,9 @@ public final void parse(Set<InputStream> mappingStreams) {
128136
catch (IOException | XMLStreamException | SAXException e) {
129137
throw LOG.getErrorParsingMappingFileException( e );
130138
}
139+
finally {
140+
run( SetContextClassLoader.action( previousTccl ) );
141+
}
131142
}
132143

133144
public final Set<Class<?>> getXmlConfiguredClasses() {
@@ -160,4 +171,14 @@ private String getSchemaResourceName(String schemaVersion) {
160171

161172
return schemaResource;
162173
}
174+
175+
/**
176+
* Runs the given privileged action, using a privileged block if required.
177+
* <p>
178+
* <b>NOTE:</b> This must never be changed into a publicly available method to avoid execution of arbitrary
179+
* privileged actions within HV's protection domain.
180+
*/
181+
private static <T> T run(PrivilegedAction<T> action) {
182+
return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run();
183+
}
163184
}

modules/src/script/setupModules.groovy

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ def appendDependency(File file, String dependencyToAppend, boolean optional) {
1717
file.write( file.text.replaceAll( /<\/dependencies>/, ' <module name="' + dependencyToAppend + '"' + ( optional ? ' optional="true"' : '' ) + '/>\n </dependencies>' ) )
1818
}
1919

20+
def removeDependency(File file, String dependencyToRemove) {
21+
file.write( file.text.replaceAll( /<module name="${dependencyToRemove}"[^\/]*\/>/, '' ) )
22+
}
23+
2024
// BV API
2125
bvModuleXml = new File( wildflyPatchedTargetDir, 'modules/system/layers/base/javax/validation/api/main/module.xml' )
2226
def bvArtifactName = 'validation-api-' + project.properties['bv.api.version'] + '.jar';
@@ -34,6 +38,11 @@ println "[INFO] Using HV version " + hvArtifactName;
3438
processFileInplace( hvModuleXml ) { text ->
3539
text.replaceAll( /hibernate-validator.*jar/, hvArtifactName )
3640
}
41+
42+
removeDependency( hvModuleXml, "org.apache.xerces" )
43+
appendDependency( hvModuleXml, "javax.xml.stream.api", false )
44+
appendDependency( hvModuleXml, "javax.api", false )
45+
3746
appendDependency( hvModuleXml, "javax.money.api", true )
3847
appendDependency( hvModuleXml, "javafx.api", true )
3948

0 commit comments

Comments
 (0)