密封.jar时密封哪些特定包装?

Mar*_*las 5 java security

当密封.jar文件(整个.jar,而不是特定的包)时,哪些包实际上是密封的?是仅包含.class文件的包,还是包含父包和子包?

举一个例子,假设我有一个包含单个.class文件com.company.city.london.class的.jar ,是否只有密封的com.company.city包?

JVM是否允许我在.jar之外创建和实例化com.company.city.building.house.class类?

JVM是否允许我在.jar之外创建和实例化com.company.world.class类?

Mar*_*las 7

好的,写完测试应用程序后,我有了答案。在阅读文档后,它们并不是我所期望的。

我将以下两个类打包到一个已密封的 .jar 中:

测试类.java:

package com.company.testjar;

public class TestClass {
}
Run Code Online (Sandbox Code Playgroud)

TestClass2.java:

package com.company.testjar2;

public class TestClass2 {
}
Run Code Online (Sandbox Code Playgroud)

.jar 清单如下所示:

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
Run Code Online (Sandbox Code Playgroud)

根据文档,密封整个 .jar 会密封 .jar 中的所有包。然而,正如我发现的那样,这种说法是模棱两可的。

然后我编写了一些 JUnit 测试用例,看看我可以定义哪些其他类而不会导致密封的 .jar 出现问题。

对于我的单元测试,我还添加了以下三个测试类。请注意,这些不是在 .jar 中定义的,而是使用相同的包结构 - 这对测试很重要。

假的.java:

package com.company.testjar;

public class Bogus {
}
Run Code Online (Sandbox Code Playgroud)

伪代码

package com.company.testjar.subpackage;

public class SubBogus {
}
Run Code Online (Sandbox Code Playgroud)

ParentBogus.java:

package com.company;

public class ParentBogus {
}
Run Code Online (Sandbox Code Playgroud)

JUnit 测试:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

各个测试应该独立运行,因为一旦加载了一个包,我就不会再次卸载它,这会影响测试的结果。如果您一次运行所有测试,则会出现失败,因为包由第一个测试加载并保持加载状态。

单独运行时,所有测试均通过。

从这些测试中,我们可以确定以下内容:

  1. 密封整个 .jar 不会密封空的父包。因此,以下空包未密封:“com”和“com.company”。只有包含类的包是密封的。请参阅测试 ParentPackage()。
  2. 如果通过实例化 .jar 中的类从 .jar 加载包,然后尝试从 .jar 外部的相同包加载类,这将失败。请参阅测试 SealedFail1()。
  3. 如果您通过实例化与 .jar 中的 .class 共享相同包名的类从 .jar 外部加载包,则尝试从同一包的密封 .jar 实例化类将失败。请参阅测试 SealedFail2()。
  4. 从密封的 .jar 实例化对象只会加载(并密封)该特定类所在的包。不会同时加载来自同一 .jar 的其他包。请参阅测试 SealedFail3()。
  5. 您可以从 .jar 成功实例化已密封和加载的包的子包中定义的对象,而不会出现问题。请参阅测试子包()。