HHH-13551 Test the retrieval of a service when an "incompatible" classloader is provided

This commit is contained in:
Yoann Rodière 2019-08-09 17:42:18 +02:00 committed by Sanne Grinovero
parent 5174fc28dc
commit f2f788c03d
5 changed files with 116 additions and 0 deletions

View File

@ -8,8 +8,11 @@ package org.hibernate.boot.registry.classloading.internal;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@ -124,6 +127,28 @@ public class ClassLoaderServiceImplTest {
csi.stop();
}
@Test
@TestForIssue(jiraKey = "HHH-13551")
public void testServiceFromIncompatibleClassLoader() {
ClassLoaderServiceImpl classLoaderService = new ClassLoaderServiceImpl(
Arrays.asList(
getClass().getClassLoader(),
/*
* This classloader will return instances of MyService where MyService
* is a different object than the one we manipulate in the current classloader.
* This used to throw an exception that triggered a boot failure in ORM,
* but should now be ignored.
*/
new IsolatedClassLoader( getClass().getClassLoader() )
),
TcclLookupPrecedence.AFTER
);
Collection<MyService> loadedServices = classLoaderService.loadJavaServices( MyService.class );
assertEquals( 1, loadedServices.size() );
}
private static class InternalClassLoader extends ClassLoader {
private List<String> names = new ArrayList<>( );

View File

@ -0,0 +1,68 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.boot.registry.classloading.internal;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import org.hibernate.bytecode.spi.ByteCodeHelper;
/**
* A classloader isolated from the application classloader,
* simulating a separate classloader that can create duplicate classes.
* This can result in a Service implementation extending
* a Service interface that is essentially the same as the one manipulated by ORM,
* but is a different Class instance and is thus deemed different by the JVM.
*/
class IsolatedClassLoader extends ClassLoader {
/**
* Another classloader from which resources will be read.
* Classes available in that classloader will be duplicated in the isolated classloader.
*/
private final ClassLoader resourceSource;
IsolatedClassLoader(ClassLoader resourceSource) {
super( getTopLevelClassLoader( resourceSource ) );
this.resourceSource = resourceSource;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
InputStream is = getResourceAsStream( name.replace( '.', '/' ) + ".class" );
if ( is == null ) {
throw new ClassNotFoundException( name + " not found" );
}
try {
byte[] bytecode = ByteCodeHelper.readByteCode( is );
return defineClass( name, bytecode, 0, bytecode.length );
}
catch( Throwable t ) {
throw new ClassNotFoundException( name + " not found", t );
}
}
@Override
public URL getResource(String name) {
return resourceSource.getResource( name );
}
@Override
public Enumeration<URL> getResources(String name) throws IOException {
return resourceSource.getResources( name );
}
private static ClassLoader getTopLevelClassLoader(ClassLoader classFileSource) {
ClassLoader result = classFileSource;
while ( result.getParent() != null ) {
result = result.getParent();
}
return result;
}
}

View File

@ -0,0 +1,12 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.boot.registry.classloading.internal;
import org.hibernate.service.Service;
public interface MyService extends Service {
}

View File

@ -0,0 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.boot.registry.classloading.internal;
public class MyServiceImpl implements MyService {
}

View File

@ -0,0 +1 @@
org.hibernate.boot.registry.classloading.internal.MyServiceImpl