/* * JBoss, Home of Professional Open Source. * Copyright 2015, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.jpa.hibernate4.scan; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.BufferedInputStream; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.ScheduledThreadPoolExecutor; import org.hibernate.jpa.boot.archive.internal.ArchiveHelper; import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptor; import org.hibernate.jpa.boot.internal.ClassDescriptorImpl; import org.hibernate.jpa.boot.scan.internal.StandardScanOptions; import org.hibernate.jpa.boot.scan.spi.AbstractScannerImpl; import org.hibernate.jpa.boot.spi.MappingFileDescriptor; import org.hibernate.jpa.test.pack.Cat; import org.hibernate.jpa.test.pack.Distributor; import org.hibernate.jpa.test.pack.Item; import org.hibernate.jpa.test.pack.Kitten; import org.hibernate.jpa.test.pack.cfgxmlpar.Morito; import org.hibernate.jpa.test.pack.defaultpar.ApplicationServer; import org.hibernate.jpa.test.pack.defaultpar.IncrementListener; import org.hibernate.jpa.test.pack.defaultpar.Lighter; import org.hibernate.jpa.test.pack.defaultpar.Money; import org.hibernate.jpa.test.pack.defaultpar.Mouse; import org.hibernate.jpa.test.pack.defaultpar.OtherIncrementListener; import org.hibernate.jpa.test.pack.defaultpar.Version; import org.hibernate.jpa.test.pack.excludehbmpar.Caipirinha; import org.hibernate.jpa.test.pack.explodedpar.Carpet; import org.hibernate.jpa.test.pack.explodedpar.Elephant; import org.hibernate.jpa.test.pack.externaljar.Scooter; import org.hibernate.jpa.test.pack.spacepar.Bug; import org.hibernate.jpa.test.pack.various.Airplane; import org.hibernate.jpa.test.pack.various.Seat; import org.jboss.as.jpa.hibernate4.VirtualFileSystemArchiveDescriptorFactory; import org.jboss.shrinkwrap.api.ArchivePath; import org.jboss.shrinkwrap.api.ArchivePaths; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.exporter.ExplodedExporter; import org.jboss.shrinkwrap.api.exporter.ZipExporter; import org.jboss.shrinkwrap.api.spec.JavaArchive; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.vfs.TempFileProvider; import org.jboss.vfs.VFS; import org.jboss.vfs.VirtualFile; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * @author Steve Ebersole */ public class ScannerTest { protected static ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); protected static ClassLoader bundleClassLoader; protected static TempFileProvider tempFileProvider; protected static File testSrcDirectory; /** * Directory where shrink-wrap built archives are written */ protected static File shrinkwrapArchiveDirectory; static { try { tempFileProvider = TempFileProvider.create("test", new ScheduledThreadPoolExecutor(2)); } catch (IOException e) { throw new RuntimeException(e); } // we make an assumption here that the directory which holds compiled classes (nested) also holds // sources. We therefore look for our module directory name, and use that to locate bundles final URL scannerTestsClassFileUrl = originalClassLoader.getResource( ScannerTest.class.getName().replace('.', '/') + ".class" ); if (scannerTestsClassFileUrl == null) { // blow up fail("Could not find ScannerTests class file url"); } // look for the module name in that url final int position = scannerTestsClassFileUrl.getFile().lastIndexOf("/hibernate4_3/"); if (position == -1) { fail("Unable to setup packaging test"); } final String moduleDirectoryPath = scannerTestsClassFileUrl.getFile().substring(0, position + "/hibernate4_3".length()); final File moduleDirectory = new File(moduleDirectoryPath); testSrcDirectory = new File(new File(moduleDirectory, "src"), "test"); final File bundlesDirectory = new File(testSrcDirectory, "bundles"); try { bundleClassLoader = new URLClassLoader(new URL[]{bundlesDirectory.toURL()}, originalClassLoader); } catch (MalformedURLException e) { fail("Unable to build custom class loader"); } shrinkwrapArchiveDirectory = new File(moduleDirectory, "target/packages"); shrinkwrapArchiveDirectory.mkdirs(); } @Before public void prepareTCCL() { // add the bundle class loader in order for ShrinkWrap to build the test package Thread.currentThread().setContextClassLoader(bundleClassLoader); } @After public void resetTCCL() throws Exception { // reset the classloader Thread.currentThread().setContextClassLoader(originalClassLoader); } protected void addPackageToClasspath(File... files) throws MalformedURLException { List<URL> urlList = new ArrayList<URL>(); for (File file : files) { urlList.add(file.toURL()); } URLClassLoader classLoader = new URLClassLoader( urlList.toArray(new URL[urlList.size()]), originalClassLoader ); Thread.currentThread().setContextClassLoader(classLoader); } protected void addPackageToClasspath(URL... urls) throws MalformedURLException { List<URL> urlList = new ArrayList<URL>(); urlList.addAll(Arrays.asList(urls)); URLClassLoader classLoader = new URLClassLoader( urlList.toArray(new URL[urlList.size()]), originalClassLoader ); Thread.currentThread().setContextClassLoader(classLoader); } protected File buildDefaultPar() { final String fileName = "defaultpar.par"; final File physicalParFile = new File(shrinkwrapArchiveDirectory, fileName); if (physicalParFile.exists()) { return physicalParFile; } JavaArchive archive = ShrinkWrap.create(JavaArchive.class, fileName); archive.addClasses( ApplicationServer.class, Lighter.class, Money.class, Mouse.class, OtherIncrementListener.class, IncrementListener.class, Version.class ); ArchivePath path = ArchivePaths.create("META-INF/orm.xml"); archive.addAsResource("defaultpar/META-INF/orm.xml", path); path = ArchivePaths.create("META-INF/persistence.xml"); archive.addAsResource("defaultpar/META-INF/persistence.xml", path); path = ArchivePaths.create("org/hibernate/jpa/test/pack/defaultpar/Mouse.hbm.xml"); archive.addAsResource("defaultpar/org/hibernate/jpa/test/pack/defaultpar/Mouse.hbm.xml", path); path = ArchivePaths.create("org/hibernate/jpa/test/pack/defaultpar/package-info.class"); archive.addAsResource("org/hibernate/jpa/test/pack/defaultpar/package-info.class", path); archive.as(ZipExporter.class).exportTo(physicalParFile, true); return physicalParFile; } protected File buildExplicitPar() { String fileName = "explicitpar.par"; JavaArchive archive = ShrinkWrap.create(JavaArchive.class, fileName); archive.addClasses( Airplane.class, Seat.class, Cat.class, Kitten.class, Distributor.class, Item.class ); ArchivePath path = ArchivePaths.create("META-INF/orm.xml"); archive.addAsResource("explicitpar/META-INF/orm.xml", path); path = ArchivePaths.create("META-INF/persistence.xml"); archive.addAsResource("explicitpar/META-INF/persistence.xml", path); File testPackage = new File(shrinkwrapArchiveDirectory, fileName); archive.as(ZipExporter.class).exportTo(testPackage, true); return testPackage; } protected File buildExplodedPar() { String fileName = "explodedpar"; JavaArchive archive = ShrinkWrap.create(JavaArchive.class, fileName); archive.addClasses( Elephant.class, Carpet.class ); ArchivePath path = ArchivePaths.create("META-INF/persistence.xml"); archive.addAsResource("explodedpar/META-INF/persistence.xml", path); path = ArchivePaths.create("org/hibernate/jpa/test/pack/explodedpar/Elephant.hbm.xml"); archive.addAsResource("explodedpar/org/hibernate/jpa/test/pack/explodedpar/Elephant.hbm.xml", path); path = ArchivePaths.create("org/hibernate/jpa/test/pack/explodedpar/package-info.class"); archive.addAsResource("org/hibernate/jpa/test/pack/explodedpar/package-info.class", path); File testPackage = new File(shrinkwrapArchiveDirectory, fileName); archive.as(ExplodedExporter.class).exportExploded(shrinkwrapArchiveDirectory); return testPackage; } protected File buildExcludeHbmPar() { String fileName = "excludehbmpar.par"; JavaArchive archive = ShrinkWrap.create(JavaArchive.class, fileName); archive.addClasses( Caipirinha.class ); ArchivePath path = ArchivePaths.create("META-INF/orm2.xml"); archive.addAsResource("excludehbmpar/META-INF/orm2.xml", path); path = ArchivePaths.create("META-INF/persistence.xml"); archive.addAsResource("excludehbmpar/META-INF/persistence.xml", path); path = ArchivePaths.create("org/hibernate/jpa/test/pack/excludehbmpar/Mouse.hbm.xml"); archive.addAsResource("excludehbmpar/org/hibernate/jpa/test/pack/excludehbmpar/Mouse.hbm.xml", path); File testPackage = new File(shrinkwrapArchiveDirectory, fileName); archive.as(ZipExporter.class).exportTo(testPackage, true); return testPackage; } protected File buildCfgXmlPar() { String fileName = "cfgxmlpar.par"; JavaArchive archive = ShrinkWrap.create(JavaArchive.class, fileName); archive.addClasses( Morito.class, Item.class ); ArchivePath path = ArchivePaths.create("META-INF/persistence.xml"); archive.addAsResource("cfgxmlpar/META-INF/persistence.xml", path); path = ArchivePaths.create("org/hibernate/jpa/test/pack/cfgxmlpar/hibernate.cfg.xml"); archive.addAsResource("cfgxmlpar/org/hibernate/jpa/test/pack/cfgxmlpar/hibernate.cfg.xml", path); File testPackage = new File(shrinkwrapArchiveDirectory, fileName); archive.as(ZipExporter.class).exportTo(testPackage, true); return testPackage; } protected File buildSpacePar() { String fileName = "space par.par"; JavaArchive archive = ShrinkWrap.create(JavaArchive.class, fileName); archive.addClasses( Bug.class ); ArchivePath path = ArchivePaths.create("META-INF/persistence.xml"); archive.addAsResource("space par/META-INF/persistence.xml", path); File testPackage = new File(shrinkwrapArchiveDirectory, fileName); archive.as(ZipExporter.class).exportTo(testPackage, true); return testPackage; } protected File buildOverridenPar() { String fileName = "overridenpar.jar"; JavaArchive archive = ShrinkWrap.create(JavaArchive.class, fileName); archive.addClasses( org.hibernate.jpa.test.pack.overridenpar.Bug.class ); ArchivePath path = ArchivePaths.create("META-INF/persistence.xml"); archive.addAsResource("overridenpar/META-INF/persistence.xml", path); path = ArchivePaths.create("overridenpar.properties"); archive.addAsResource("overridenpar/overridenpar.properties", path); File testPackage = new File(shrinkwrapArchiveDirectory, fileName); archive.as(ZipExporter.class).exportTo(testPackage, true); return testPackage; } protected File buildExternalJar() { String fileName = "externaljar.jar"; JavaArchive archive = ShrinkWrap.create(JavaArchive.class, fileName); archive.addClasses( Scooter.class ); ArchivePath path = ArchivePaths.create("META-INF/orm.xml"); archive.addAsResource("externaljar/META-INF/orm.xml", path); File testPackage = new File(shrinkwrapArchiveDirectory, fileName); archive.as(ZipExporter.class).exportTo(testPackage, true); return testPackage; } protected File buildLargeJar() { final String fileName = "large.jar"; final JavaArchive archive = ShrinkWrap.create(JavaArchive.class, fileName); // Build a large jar by adding a lorem ipsum file repeatedly. final File loremipsumTxtFile = new File(testSrcDirectory, "resources/org/hibernate/jpa/test/packaging/loremipsum.txt"); for (int i = 0; i < 100; i++) { ArchivePath path = ArchivePaths.create("META-INF/file" + i); archive.addAsResource(loremipsumTxtFile, path); } File testPackage = new File(shrinkwrapArchiveDirectory, fileName); archive.as(ZipExporter.class).exportTo(testPackage, true); return testPackage; } protected File buildWar() { String fileName = "war.war"; WebArchive archive = ShrinkWrap.create(WebArchive.class, fileName); archive.addClasses( org.hibernate.jpa.test.pack.war.ApplicationServer.class, org.hibernate.jpa.test.pack.war.IncrementListener.class, org.hibernate.jpa.test.pack.war.Lighter.class, org.hibernate.jpa.test.pack.war.Money.class, org.hibernate.jpa.test.pack.war.Mouse.class, org.hibernate.jpa.test.pack.war.OtherIncrementListener.class, org.hibernate.jpa.test.pack.war.Version.class ); ArchivePath path = ArchivePaths.create("WEB-INF/classes/META-INF/orm.xml"); archive.addAsResource("war/WEB-INF/classes/META-INF/orm.xml", path); path = ArchivePaths.create("WEB-INF/classes/META-INF/persistence.xml"); archive.addAsResource("war/WEB-INF/classes/META-INF/persistence.xml", path); path = ArchivePaths.create("WEB-INF/classes/org/hibernate/jpa/test/pack/war/Mouse.hbm.xml"); archive.addAsResource("war/WEB-INF/classes/org/hibernate/jpa/test/pack/war/Mouse.hbm.xml", path); File testPackage = new File(shrinkwrapArchiveDirectory, fileName); archive.as(ZipExporter.class).exportTo(testPackage, true); return testPackage; } protected File buildNestedEar(File includeFile) { String fileName = "nestedjar.ear"; JavaArchive archive = ShrinkWrap.create(JavaArchive.class, fileName); archive.addAsResource(includeFile); File testPackage = new File(shrinkwrapArchiveDirectory, fileName); archive.as(ZipExporter.class).exportTo(testPackage, true); return testPackage; } protected File buildNestedEarDir(File includeFile) { String fileName = "nesteddir.ear"; JavaArchive archive = ShrinkWrap.create(JavaArchive.class, fileName); archive.addAsResource(includeFile); File testPackage = new File(shrinkwrapArchiveDirectory, fileName); archive.as(ExplodedExporter.class).exportExploded(shrinkwrapArchiveDirectory); return testPackage; } @Test public void testHttp() throws Exception { URL url = ArchiveHelper.getJarURLFromURLEntry( new URL( "jar:http://www.ibiblio.org/maven/hibernate/jars/hibernate-annotations-3.0beta1.jar!/META-INF/persistence.xml" ), "/META-INF/persistence.xml" ); try { URLConnection urlConnection = url.openConnection(); urlConnection.connect(); } catch (IOException ie) { //fail silently return; } ArchiveDescriptor archiveDescriptor = VirtualFileSystemArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor(url); AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector(new StandardScanOptions()); archiveDescriptor.visitArchive( new AbstractScannerImpl.ArchiveContextImpl( new PersistenceUnitDescriptorAdapter(), true, resultCollector ) ); assertEquals(0, resultCollector.getClassDescriptorSet().size()); assertEquals(0, resultCollector.getPackageDescriptorSet().size()); assertEquals(0, resultCollector.getMappingFileSet().size()); } @Test public void testInputStreamZippedJar() throws Exception { File defaultPar = buildDefaultPar(); addPackageToClasspath(defaultPar); final VirtualFile virtualFile = VFS.getChild(defaultPar.getAbsolutePath()); Closeable closeable = VFS.mountZip(virtualFile, virtualFile, tempFileProvider); try { ArchiveDescriptor archiveDescriptor = VirtualFileSystemArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor(defaultPar.toURI().toURL()); AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector(new StandardScanOptions()); archiveDescriptor.visitArchive( new AbstractScannerImpl.ArchiveContextImpl( new PersistenceUnitDescriptorAdapter(), true, resultCollector ) ); validateResults(resultCollector, ApplicationServer.class, Version.class); } finally { closeable.close(); } } private void validateResults(AbstractScannerImpl.ResultCollector resultCollector, Class... expectedClasses) throws IOException { assertEquals(3, resultCollector.getClassDescriptorSet().size()); for (Class expectedClass : expectedClasses) { assertTrue( resultCollector.getClassDescriptorSet().contains( new ClassDescriptorImpl(expectedClass.getName(), null) ) ); } assertEquals(2, resultCollector.getMappingFileSet().size()); for (MappingFileDescriptor mappingFileDescriptor : resultCollector.getMappingFileSet()) { assertNotNull(mappingFileDescriptor.getStreamAccess()); final InputStream stream = mappingFileDescriptor.getStreamAccess().accessInputStream(); assertNotNull(stream); stream.close(); } } @Test public void testNestedJarProtocol() throws Exception { File defaultPar = buildDefaultPar(); File nestedEar = buildNestedEar(defaultPar); addPackageToClasspath(nestedEar); final VirtualFile nestedEarVirtualFile = VFS.getChild(nestedEar.getAbsolutePath()); Closeable closeable = VFS.mountZip(nestedEarVirtualFile, nestedEarVirtualFile, tempFileProvider); try { VirtualFile parVirtualFile = nestedEarVirtualFile.getChild("defaultpar.par"); Closeable closeable2 = VFS.mountZip(parVirtualFile, parVirtualFile, tempFileProvider); try { ArchiveDescriptor archiveDescriptor = VirtualFileSystemArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor(parVirtualFile.toURL()); AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector(new StandardScanOptions()); archiveDescriptor.visitArchive( new AbstractScannerImpl.ArchiveContextImpl( new PersistenceUnitDescriptorAdapter(), true, resultCollector ) ); validateResults(resultCollector, ApplicationServer.class, Version.class); } finally { closeable2.close(); } } finally { closeable.close(); } File nestedEarDir = buildNestedEarDir(defaultPar); final VirtualFile nestedEarDirVirtualFile = VFS.getChild(nestedEarDir.getAbsolutePath()); try { VirtualFile parVirtualFile = nestedEarDirVirtualFile.getChild("defaultpar.par"); closeable = VFS.mountZip(parVirtualFile, parVirtualFile, tempFileProvider); try { ArchiveDescriptor archiveDescriptor = VirtualFileSystemArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor(parVirtualFile.toURL()); AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector(new StandardScanOptions()); archiveDescriptor.visitArchive( new AbstractScannerImpl.ArchiveContextImpl( new PersistenceUnitDescriptorAdapter(), true, resultCollector ) ); validateResults(resultCollector, ApplicationServer.class, Version.class); } finally { closeable.close(); } } finally { closeable.close(); } } @Test public void testJarProtocol() throws Exception { File war = buildWar(); addPackageToClasspath(war); final VirtualFile warVirtualFile = VFS.getChild(war.getAbsolutePath()); Closeable closeable = VFS.mountZip(warVirtualFile, warVirtualFile, tempFileProvider); try { ArchiveDescriptor archiveDescriptor = VirtualFileSystemArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( warVirtualFile.toURL() ); AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector(new StandardScanOptions()); archiveDescriptor.visitArchive( new AbstractScannerImpl.ArchiveContextImpl( new PersistenceUnitDescriptorAdapter(), true, resultCollector ) ); validateResults( resultCollector, org.hibernate.jpa.test.pack.war.ApplicationServer.class, org.hibernate.jpa.test.pack.war.Version.class ); } finally { closeable.close(); } } @Test public void testZippedJar() throws Exception { File defaultPar = buildDefaultPar(); addPackageToClasspath(defaultPar); final VirtualFile virtualFile = VFS.getChild(defaultPar.getAbsolutePath()); Closeable closeable = VFS.mountZip(virtualFile, virtualFile, tempFileProvider); try { ArchiveDescriptor archiveDescriptor = VirtualFileSystemArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( virtualFile.toURL() ); AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector(new StandardScanOptions()); archiveDescriptor.visitArchive( new AbstractScannerImpl.ArchiveContextImpl( new PersistenceUnitDescriptorAdapter(), true, resultCollector ) ); validateResults(resultCollector, ApplicationServer.class, Version.class); } finally { closeable.close(); } } @Test public void testExplodedJar() throws Exception { File explodedPar = buildExplodedPar(); addPackageToClasspath(explodedPar); String dirPath = explodedPar.getAbsolutePath(); if (dirPath.endsWith("/")) { dirPath = dirPath.substring(0, dirPath.length() - 1); } final VirtualFile virtualFile = VFS.getChild(dirPath); ArchiveDescriptor archiveDescriptor = VirtualFileSystemArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( virtualFile.toURL() ); AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector(new StandardScanOptions()); archiveDescriptor.visitArchive( new AbstractScannerImpl.ArchiveContextImpl( new PersistenceUnitDescriptorAdapter(), true, resultCollector ) ); assertEquals(1, resultCollector.getClassDescriptorSet().size()); assertEquals(1, resultCollector.getPackageDescriptorSet().size()); assertEquals(1, resultCollector.getMappingFileSet().size()); assertTrue( resultCollector.getClassDescriptorSet().contains( new ClassDescriptorImpl(Carpet.class.getName(), null) ) ); for (MappingFileDescriptor mappingFileDescriptor : resultCollector.getMappingFileSet()) { assertNotNull(mappingFileDescriptor.getStreamAccess()); final InputStream stream = mappingFileDescriptor.getStreamAccess().accessInputStream(); assertNotNull(stream); stream.close(); } } @Test public void testGetBytesFromInputStream() throws Exception { File file = buildLargeJar(); long start = System.currentTimeMillis(); InputStream stream = new BufferedInputStream( new FileInputStream(file)); int oldLength = getBytesFromInputStream(stream).length; stream.close(); long oldTime = System.currentTimeMillis() - start; start = System.currentTimeMillis(); stream = new BufferedInputStream(new FileInputStream(file)); int newLength = ArchiveHelper.getBytesFromInputStream(stream).length; stream.close(); long newTime = System.currentTimeMillis() - start; assertEquals(oldLength, newLength); assertTrue(oldTime > newTime); } // This is the old getBytesFromInputStream from JarVisitorFactory before // it was changed by HHH-7835. Use it as a regression test. private byte[] getBytesFromInputStream(InputStream inputStream) throws IOException { int size; byte[] entryBytes = new byte[0]; for (; ; ) { byte[] tmpByte = new byte[4096]; size = inputStream.read(tmpByte); if (size == -1) { break; } byte[] current = new byte[entryBytes.length + size]; System.arraycopy(entryBytes, 0, current, 0, entryBytes.length); System.arraycopy(tmpByte, 0, current, entryBytes.length, size); entryBytes = current; } return entryBytes; } @Test public void testGetBytesFromZeroInputStream() throws Exception { // Ensure that JarVisitorFactory#getBytesFromInputStream // can handle 0 length streams gracefully. URL emptyTxtUrl = getClass().getResource("/org/hibernate/jpa/test/packaging/empty.txt"); if (emptyTxtUrl == null) { throw new RuntimeException("Bah!"); } InputStream emptyStream = new BufferedInputStream(emptyTxtUrl.openStream()); int length = ArchiveHelper.getBytesFromInputStream(emptyStream).length; assertEquals(length, 0); emptyStream.close(); } }