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

时间:2017-02-23 11:00:19

标签: java security

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

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

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

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

1 个答案:

答案 0 :(得分:4)

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

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

TestClass.java:

package com.company.testjar;

public class TestClass {
}

TestClass2.java:

package com.company.testjar2;

public class TestClass2 {
}

.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

根据文档,密封整个.jar密封.jar中的所有包装。但是,我发现这句话含糊不清。

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

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

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 {
}

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();
    }
}

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

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

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

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