When sealing a .jar file (the whole .jar, not specific packages), which packages are actually sealed? Is it only the packages that contain .class files, or does it also include parent packages and sub-packages?
To give an example, say I have a .jar containing the single .class file com.company.city.london.class, is it only the com.company.city package that is sealed?
Would the JVM allow me to create and instantiate the class com.company.city.building.house.class outside of the .jar?
Would the JVM allow me to create and instantiate the class com.company.world.class outside of the .jar?
OK, after writing a test application, I have the answers. And they weren't quite what I had expected after reading the documentation.
I have the following two classes packaged into a .jar that has been sealed:
TestClass.java:
package com.company.testjar;
public class TestClass {
}
TestClass2.java:
package com.company.testjar2;
public class TestClass2 {
}
The .jar manifest looks like this:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.9.3
Created-By: 1.8.0_40-b26 (Oracle Corporation)
Implementation-Vendor: Company
Implementation-Title: Test Jar
Implementation-Version: 6.4.0.0
Sealed: true
According to the documentation, sealing the entire .jar seals ALL packages within the .jar. However, this statement is ambiguous as I found out.
I then wrote some JUnit test cases to see what other classes I could define without causing issues with the sealed .jar.
For my unit tests, I also added the following three test classes. Note that these are NOT defined in the .jar, but do use the same package structure - this is important for the tests.
Bogus.java:
package com.company.testjar;
public class Bogus {
}
SubBogus.java
package com.company.testjar.subpackage;
public class SubBogus {
}
ParentBogus.java:
package com.company;
public class ParentBogus {
}
The JUnit tests:
package com.company.test;
import static org.junit.Assert.*;
import org.junit.Test;
import com.company.ParentBogus;
import com.company.testjar.Bogus;
import com.company.testjar.TestClass;
import com.company.testjar.subpackage.SubBogus;
import com.company.testjar2.TestClass2;
/**
* A set of tests for testing the effects of .jar sealing.
*
* These tests rely on a built .jar named TestJar.jar which is built from the command line.
*
* Only one of these tests can be run at a time because one a package has been loaded, it cannot
* be unloaded again. Because of this, each test must be run separately.
*/
public class TestPackages {
@Test
public void SealedFail1() {
// Instantiate instance of TestClass from sealed .jar.
TestClass t = new TestClass();
// Following should blow up because package com.company.testjar has already
// been loaded by instantiating TestClass above.
try {
new Bogus();
// Should not get here. Throw if we do.
assertFalse(true);
} catch (SecurityException ex) {
// Expected.
}
}
@Test
public void SealedFail2() {
Bogus b = new Bogus();
// Following should blow up because package com.company.testjar has already
// been loaded by instantiating Bogus above.
try {
new TestClass();
// Should not get here. Throw if we do.
assertFalse(true);
} catch (SecurityException ex) {
// Expected.
}
}
/**
* Test to see if instantiating object from package in a sealed .jar will effectively
* load and seal all packages in that .jar.
*/
@Test
public void SealedFail3() {
// Instantiate object from com.company.testjar2 package. This package will now be
// loaded and sealed.
TestClass2 t2 = new TestClass2();
// Instantiate object from com.company.testjar package NOT from sealed .jar.
// This should work because this package has not been sealed yet!
Bogus b = new Bogus();
// This should now throw because the com.company.testjar package has already
// been loaded by instantiating Bogus above, and the TestClass is from that
// same package from the sealed .jar.
try {
new TestClass();
// Should not get here. Throw if we do.
assertFalse(true);
} catch (SecurityException ex) {
// Expected.
}
}
/**
* Test to see if instantiating an object from a sealed .jar prevents us from then
* instantiating an instance of an object from a sub-package NOT defined in the
* same .jar.
*/
@Test
public void SubPackage() {
// Instantiate instance of TestClass from sealed .jar. Loads and seals the
// com.company.testjar package.
TestClass t = new TestClass();
// Now attempt to instantiate an instance of an object from a sub-package of
// com.company.testjar which is not defined in the same .jar.
new SubBogus();
}
/**
* Test to see if instantiating an object from a sealed .jar prevents us from then
* instantiating an instance of an object from a parent package NOT defined in the
* same .jar.
*/
@Test
public void ParentPackage() {
// Instantiate instance of TestClass from sealed .jar. Loads and seals the
// com.company.testjar package.
TestClass t = new TestClass();
// Now attempt to instantiate an instance of an object from the parent-package of
// com.company.testjar which is not defined in the same .jar.
new ParentBogus();
}
}
The individual tests should be run independently because once a package has been loaded, I'm not unloading it again and would affect the result of the tests. If you run all the tests in once go, there will be failures because packages are loaded by the first test and stay loaded.
All of the tests pass when run individually.
From these tests, we can determine the following:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With