Skip to content

Commit

Permalink
HV-1280 Setting context class loader to HV's defining CL before calli…
Browse files Browse the repository at this point in the history
…ng into JAXB/JAXP;

This makes sure we don't get in touch with a JAXP implementation provided as part of the
deployed application when running on WF.
  • Loading branch information
gunnarmorling authored and gsmet committed Mar 14, 2017
1 parent a8db9cd commit 27370d3
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@ public final BootstrapConfiguration parseValidationXml() {
return BootstrapConfigurationImpl.getDefaultBootstrapConfiguration();
}

ClassLoader previousTccl = Thread.currentThread().getContextClassLoader();

try {
Thread.currentThread().setContextClassLoader( ValidationXmlParser.class.getClassLoader() );

// HV-970 The parser helper is only loaded if there actually is a validation.xml file;
// this avoids accessing javax.xml.stream.* (which does not exist on Android) when not actually
// working with the XML configuration
Expand All @@ -83,6 +87,7 @@ public final BootstrapConfiguration parseValidationXml() {
return createBootstrapConfiguration( validationConfig );
}
finally {
Thread.currentThread().setContextClassLoader( previousTccl );
closeStream( inputStream );
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,7 @@ public final void parse(Set<InputStream> mappingStreams) {
in.mark( Integer.MAX_VALUE );
}

XMLEventReader xmlEventReader = xmlParserHelper.createXmlEventReader( "constraint mapping file", new CloseIgnoringInputStream( in ) );
String schemaVersion = xmlParserHelper.getSchemaVersion( "constraint mapping file", xmlEventReader );
String schemaResourceName = getSchemaResourceName( schemaVersion );
Schema schema = xmlParserHelper.getSchema( schemaResourceName );

Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setSchema( schema );

ConstraintMappingsType mapping = getValidationConfig( xmlEventReader, unmarshaller );
ConstraintMappingsType mapping = unmarshal( jc, in );
String defaultPackage = mapping.getDefaultPackage();

parseConstraintDefinitions(
Expand Down Expand Up @@ -180,6 +172,27 @@ public final void parse(Set<InputStream> mappingStreams) {
}
}

private ConstraintMappingsType unmarshal(JAXBContext jc, InputStream in) throws JAXBException {
ClassLoader previousTccl = Thread.currentThread().getContextClassLoader();

try {
Thread.currentThread().setContextClassLoader( ValidationXmlParser.class.getClassLoader() );

XMLEventReader xmlEventReader = xmlParserHelper.createXmlEventReader( "constraint mapping file", new CloseIgnoringInputStream( in ) );
String schemaVersion = xmlParserHelper.getSchemaVersion( "constraint mapping file", xmlEventReader );
String schemaResourceName = getSchemaResourceName( schemaVersion );
Schema schema = xmlParserHelper.getSchema( schemaResourceName );

Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setSchema( schema );

return getValidationConfig( xmlEventReader, unmarshaller );
}
finally {
Thread.currentThread().setContextClassLoader( previousTccl );
}
}

public final Set<Class<?>> getXmlConfiguredClasses() {
return processedClasses;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.integration.wildfly.xml;

/**
* @author Gunnar Morling
*/
public class Camera {

public String brand = null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.integration.wildfly.xml;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;

import java.util.Set;

import javax.inject.Inject;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.constraints.NotNull;

import org.jboss.arquillian.container.test.api.Deployer;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.junit.InSequence;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.Asset;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.jboss.shrinkwrap.descriptor.api.Descriptors;
import org.jboss.shrinkwrap.descriptor.api.validationConfiguration11.ValidationConfigurationDescriptor;
import org.jboss.shrinkwrap.descriptor.api.validationMapping11.ValidationMappingDescriptor;
import org.jboss.shrinkwrap.resolver.api.maven.Maven;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
* Test for https://hibernate.atlassian.net/browse/HV-1280. To reproduce the issue, the deployment must be done twice
* (it will only show up during the 2nd deploy), which is why the test is managing the deployment itself via client-side
* test methods.
*
* @author Gunnar Morling
*/
@RunWith(Arquillian.class)
public class JaxpContainedInDeploymentIT {

private static final String WAR_FILE_NAME = JaxpContainedInDeploymentIT.class.getSimpleName() + ".war";

@ArquillianResource
private Deployer deployer;

@Inject
private Validator validator;

@Deployment(name = "jaxpit", managed = false)
public static Archive<?> createTestArchive() {
return ShrinkWrap
.create( WebArchive.class, WAR_FILE_NAME )
.addClass( Camera.class )
.addAsResource( validationXml(), "META-INF/validation.xml" )
.addAsResource( mappingXml(), "META-INF/my-mapping.xml" )
.addAsLibrary( Maven.resolver().resolve( "xerces:xercesImpl:2.9.1" ).withoutTransitivity().asSingleFile() )
.addAsResource( "log4j.properties" )
.addAsWebInfResource( EmptyAsset.INSTANCE, "beans.xml" );
}

private static Asset validationXml() {
String validationXml = Descriptors.create( ValidationConfigurationDescriptor.class )
.version( "1.1" )
.constraintMapping( "META-INF/my-mapping.xml" )
.exportAsString();
return new StringAsset( validationXml );
}

private static Asset mappingXml() {
String mappingXml = Descriptors.create( ValidationMappingDescriptor.class )
.version( "1.1" )
.createBean()
.clazz( Camera.class.getName() )
.createField()
.name( "brand" )
.createConstraint()
.annotation( "javax.validation.constraints.NotNull" )
.up()
.up()
.up()
.exportAsString();
return new StringAsset( mappingXml );
}

@Test
@RunAsClient
@InSequence(0)
public void deploy1() throws Exception {
deployer.deploy( "jaxpit" );
}

@Test
@InSequence(1)
public void test1() throws Exception {
doTest();
}

@Test
@RunAsClient
@InSequence(2)
public void undeploy1() throws Exception {
deployer.undeploy( "jaxpit" );
}

@Test
@RunAsClient
@InSequence(3)
public void deploy2() throws Exception {
deployer.deploy( "jaxpit" );
}

@Test
@InSequence(4)
public void test2() throws Exception {
doTest();
}

@Test
@RunAsClient
@InSequence(5)
public void undeploy2() throws Exception {
deployer.undeploy( "jaxpit" );
}

private void doTest() {
Set<ConstraintViolation<Camera>> violations = validator.validate( new Camera() );

assertEquals( 1, violations.size() );
assertSame( NotNull.class, violations.iterator()
.next()
.getConstraintDescriptor()
.getAnnotation()
.annotationType() );
}
}

0 comments on commit 27370d3

Please sign in to comment.